题解:因为题目是给出来顺时针,任意取两个坐标h[i],h[j]时如果所有的点在他的右侧就可以有跳i->j的有向边并且路径长度为1,如果所有的点在他的左侧的时候就可以有一条j->i的边并且路径长度为1。
如果所有的点都在边上就可以建一条双向边
然后跑一边Floyd算法就可以求出以i为起点i为终点的最短路径
然后去其中的最小值ans,如果ans>m就包不了,否则m-ans就是答案
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int inf = 0x3f3f3f3f;
const int mx = 505;
typedef long long int ll;
struct point{
int x,y;
point operator-(const point &a){
point c;
c.x = x-a.x;
c.y = y-a.y;
return c;
}
ll operator*(const point &a){
// cout<<x*a.y-y*a.x;
return 1ll*x*a.y-y*a.x;
}
}h[mx],s[mx];
int dis[mx][mx];
bool judge(point a,point b,point c){
int maxy = max(a.y,b.y);
int miny = min(a.y,b.y);
int maxx = max(a.x,b.x);
int minx = min(a.x,b.x);
if(!(c.x>=minx&&c.x<=maxx))
return true;
if(!(c.y>=miny&&c.y<=maxy))
return true;
return false;
}
int main(){
int n,m;
while(~scanf("%d",&n)){
for(int i = 1; i <= n; i++)
scanf("%d%d",&s[i].x,&s[i].y);
int m;
memset(dis,inf,sizeof(dis));
scanf("%d",&m);
for(int i = 1; i <= m; i++)
scanf("%d%d",&h[i].x,&h[i].y);
for(int i = 1; i <= m; i++)
for(int j = 1; j <= m; j++){
int ok = 1;
if(i==j)
continue;
for(int k = 1; k <= n; k++){
long long int sum = (h[j]-h[i])*(s[k]-h[i]);
//cout<<sum<<endl;
if(sum>0||(sum==0&&judge(h[i],h[j],s[k]))){
ok = 0;
break;
}
}
if(ok){
//printf("%d %d\n",i,j);
dis[i][j] = 1;
}
}
for(int k = 1; k <= m; k++)
for(int i = 1; i <= m; i++){
if(dis[i][k]==inf)
continue;
for(int j = 1; j <= m; j++)
dis[i][j] = min(dis[i][j],dis[i][k]+dis[k][j]);
}
int ans = inf;
for(int i = 1; i <= m; i++){
//cout<<dis[i][i]<<endl;
ans = min(ans,dis[i][i]);
}
if(ans>m)
puts("ToT");
else
printf("%d\n",m-ans);
}
return 0;
}