题意:给出N个点,你从第一个给出的点出发,每次只能经过未经过的点且行走的距离要大于上一次行走的距离(第一次行走不限)。当有人无法再进行操作时输。
思路:暴力存储每两个点之间的距离并排序。然后从最大的那条边开始,把他的两个端点标记(有多条就全部标记),再标记两个端点都未标记过的次大边,,直到所有边都操作完毕。最后看1是否标记来判断输赢。
原因:某个人在最大边时,如果在其中一个端点,那么对手可以走到另一个端点,这是必败态。在次大边的一个端点时,对手可以走到次大边的另一个端点。那么只能走到最大边的一个端点或者无路可走,递归到上一个状态,也是必败态。

#include<iostream> #include<cstring> #include<algorithm> #include<cstdio> #include<cmath> #include<map> #include<queue> #include<vector> #include<string> #define ll long long #define PI acos(-1.0) #define F first #define S second #define pb push_back #define debug(x); printf("debug%d ",x); #define des(x); printf("des:%s ",x+1); const ll INF=0x3f3f3f3f3f3f3f3f; const int inf=0x3f3f3f3f; const ll mod=1e9+7; using namespace std; const int N=2020202; struct node { ll x,y; //ll val; }q[2020]; struct node1 { int u,v; ll val; }arr[N]; int vis[2020]; int n,t; bool cmp(node1 a,node1 b) { return a.val>b.val; } ll juli(int i,int j) { return (q[i].x-q[j].x)*(q[i].x-q[j].x)+(q[i].y-q[j].y)*(q[i].y-q[j].y); } int main() { scanf("%d",&t); while(t--) { memset(vis,0,sizeof vis); scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%lld%lld",&q[i].x,&q[i].y); } int cnt=0; for(int i=1;i<n;i++) { for(int j=i+1;j<=n;j++) { arr[++cnt].val=juli(i,j); arr[cnt].u=i; arr[cnt].v=j; } } sort(arr+1,arr+1+cnt,cmp); int pos=1; while(pos<=cnt) { int pre=pos; while(arr[pos].val==arr[pre].val) pos++; for(int i=pre;i<pos;i++) { if(!vis[arr[i].u]&&!vis[arr[i].v]) { vis[arr[i].u]=1; vis[arr[i].v]=1; } } } if(vis[1]) printf("YES "); else printf("NO "); } return 0; }