2020杭电多校第7场 1007 Game

原题链接
题意:
有一个二维平面,上面有n个点,在第一个点上有一颗石头。现在有两个人做游戏,他们轮流移动石头,
第一次移动的时候可以将石头移动到平面上的其他任何的点上。之后的每次移动,可以将石头移动到比上次移动距离更远的点上。
当轮到某人时,他无法再移动石头,则判他为输。

做法:
我们先考虑第一步:当前是第一个点,如果说第一个点和其他的某个点是平面中最长距离的点对,则先手必胜。
同样:也就是说,如果当前点在目前平面上和其他某个点能组成为最长点对的话,当前这个人必胜。
那么我们可以反着处理一下,在计算所有点对之间的距离后,按照距离从大到小排序之后遍历所有点对,如果我们在遍历点对的途中,
发现点1已经被遍历过了并且剩下的点的个数大于1,则先手必胜,否则必败。

#include <bits/stdc++.h>
#define DEBUG
#define d1(x) std::cout << #x " = " << (x) << std::endl
#define d2(x, y) std::cout << #x " = " << (x) << " ," #y " = " << (y) << std::endl
#define disp(arry, fr, to) 
    { 
        std::cout << #arry " : "; 
        for(int _i = fr; _i <= to; _i++) std::cout << arry[_i] << " "; 
        std::cout << std::endl; 
    }

#define ed end()
#define bg begin()
#define mkp make_pair
#define pb push_back
#define v(T) vector<T>
#define all(x) x.bg,x.ed
#define newline puts("")
#define si(x) ((int)x.size())
#define rep(i,n) for(int i=1;i<=n;++i)
#define rrep(i,n) for(int i=0;i<n;++i)
#define srep(i,s,t) for(int i=s;i<=t;++i)

using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn = 5e6+10;
const int inf = 0x7f7f7f7f;
const ll inf_ll = 1ll*inf*inf;
const int Mod = 1e9+7;
const double eps = 1e-7;
int n;
double a[2010],b[2010];
struct node{
    int x,y;
    double dis;
}e[maxn];
double cdis(double x1,double y1,double x2,double y2){
    return sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
}
bool cmp(node a,node b){return a.dis>b.dis;}
bool vis[maxn];

int main(){
    // freopen("1.out","w",stdout);
    int T;
    scanf("%d",&T);
    for(int _=1;_<=T;_++)
    {
        scanf("%d",&n);
        rep(i,n){
            scanf("%lf%lf",&a[i],&b[i]);
            vis[i]=0;
        }
        int cnt=0;
        rep(i,n){
            for (int j=i+1;j<=n;j++){
                double dis=cdis(a[i],b[i],a[j],b[j]);
                e[++cnt].dis=dis;
                e[cnt].x=i;
                e[cnt].y=j;
            }
        }
        sort(e+1,e+cnt+1,cmp);
        // rep(i,cnt){
        //     d2(i,e[i].dis);
        // }
        int flag=0;
        int sum = n;
        rep(i,cnt){
            int x=e[i].x,y=e[i].y;
            if(!vis[x] && !vis[y]){
                vector<int>G; 
                int j = i;
                while(j<=cnt && e[j].dis == e[i].dis){
                    int u=e[j].x,v=e[j].y;
                    if(vis[u] || vis[v]){
                        j++;continue;
                    }
                    G.push_back(u),G.push_back(v),j++;
                }
                i=j-1;
                for (auto v : G){
                    vis[v]=1;
                }
                if(vis[1] == 1 && sum > 1) flag=1;
                sum-=G.size();
            }
            if(flag) break;
        }
        // d1(flag);
        if(flag) puts("YES");
        else puts("NO");
    }
    return 0;
}
点击展开代码块
你将不再是道具,而是成为人如其名的人
原文地址:https://www.cnblogs.com/wsl-lld/p/13540542.html