[BZOJ2927][Poi1999]多边形之战(博弈)

题目描述

传送门

题解

有邻边的多边形连边,问题转化为一棵树,有一个节点是黑色节点,每次删除一个叶子节点,能删掉黑色节点的人获胜
把黑色节点看做根
如果黑色节点只有一个儿子,先手必胜①
只有三个点并且一个黑色节点只有两个儿子,先手必败②
如果节点要是再多,并且黑色节点有多于两个儿子,那么如果有奇数个白点,先手一定能删除到先手必败的情况②,先手必胜
如果有偶数个白点,后手一定能删除到先手必败的情况②,先手必败

代码

#include
#include
#include
#include
#include
using namespace std;
#define N 50005

int n,x,y,z,cnt,son;
int f[N];
struct hp{int x,y,id;}e[N*3];

int cmp(hp a,hp b)
{
    return a.xint find(int x)
{
    if (x==f[x]) return x;
    f[x]=find(f[x]);
    return f[x];
}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n-2;++i)
    {
        scanf("%d%d%d",&x,&y,&z);
        if (x>y) swap(x,y);
        if (y>z) swap(y,z);
        if (x>y) swap(x,y);
        e[++cnt].x=x,e[cnt].y=y,e[cnt].id=i;
        e[++cnt].x=y,e[cnt].y=z,e[cnt].id=i;
        e[++cnt].x=x,e[cnt].y=z,e[cnt].id=i;
    }
    sort(e+1,e+cnt+1,cmp);
    for (int i=1;i<=n-2;++i) f[i]=i;
    for (int i=2;i<=cnt;++i)
        if (e[i-1].x==e[i].x&&e[i-1].y==e[i].y&&find(e[i-1].id)!=find(e[i].id))
        {
            f[find(e[i].id)]=find(e[i-1].id);
            if (e[i].id==1||e[i-1].id==1) ++son;
        }
    if (son<=1) puts("TAK");
    else
    {
        if (n%2) puts("NIE");
        else puts("TAK");
    }
}

总结

①这种多边形问题大多可以转化为树的问题

你可能感兴趣的:(题解,博弈)