BZOJ 2927: [Poi1999]多边形之战 【博弈分析】

题目描述:

多边形之战是一个双人游戏。游戏在一个有n个顶点的凸多边形上进行,这个凸多边形的n-3条对角线将多边形分成n-2个三角形,这n-3条对角线在多边形的顶点相交。三角形中的一个被染成黑色,其余是白色。双方轮流进行游戏,当轮到一方时,他必须沿着画好的对角线,从多边形上切下一个三角形。切下黑色三角形的一方获胜。

题目分析:

嗯,题面的沿着画好的对角线的意思是,当你切一个三角形的时候,必须保证它的两条边都在当前多边形的边上。也就是从外到内切。

把三角形看做一个点,如果两个三角形有公共边,那么就在两个点间连一条边,会发现这些点构成了一棵树。类似于平面图转对偶图?
可以发现,一个三角形可以切当且仅当它在树中对应的点是叶节点,并且一个点最多有三个邻接点。
把黑点看做根节点,那么有:

  • 如果一开始黑点只有一个儿子,那么先手必胜。
  • 否则,黑点必然有>=2个儿子
    • 若黑点下面有奇数个白点,先手一定可以在保证黑点儿子数>1的情况下把白点取成偶数个,最后的状态就是黑点下面只剩一个儿子,那么这个状态一定是后手取出来的,先手就可以把黑点取走获胜了。
    • 若一开始黑点下面有偶数个白点,先手只能把局面转成上面两种情况中的一种,先手必败。

所以先手的胜负就只与黑三角形的邻接三角形个数以及三角形个数的奇偶性有关了

判断邻接只要看是否有两个点编号相同(有公共边)即可。
Code:

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
using namespace std;
template<class T>inline void read(T &a){
    char c;while(!isdigit(c=getchar()));
    for(a=c-'0';isdigit(c=getchar());a=a*10+c-'0');
}
int n,x,y,z,v[50005],d;
int main()
{
    read(n),n-=3;
    if(n&1) return puts("TAK"),0;
    read(x),read(y),read(z),v[x]=v[y]=v[z]=1;
    for(int i=1;i<=n;i++) read(x),read(y),read(z),d+=(v[x]+v[y]+v[z]==2);
    if(d==1) puts("TAK");
    else puts("NIE");
}

PS:由于这道题的三角形编号是连续的,所以可以直接看黑色三角形的每条边的两个点编号是否连续就可以判断在这条边上有没有邻接三角形了 由于博主很懒就不贴出代码了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值