问题描述:
多边形游戏是一个双人游戏。游戏在一个有n个顶点的凸多边形上进行,这个凸多边形的n-3条对角线将多边形分成n-2个三角形,三角形中的一个被染成黑色,其余是白色。双方轮流进行游戏,当轮到一方时,他必须沿着画好的对角线,从多边形上切下一个三角形。切下黑色三角形的一方获胜。
输入
多组测试数据。每组测试数据第一行n,表示顶点数。多边形的顶点从0到n-1顺时针标号,接着的n-2行描述组成多边形的三角形,且第一行给出的是黑色三角形的描述。当n=0时表示输入结束。
输出
对每组测试数据,输出YES或NO:YES,表示先走的一方有必胜策略;NO,表示先走的一方没有必胜策略。
样例
1
6
0 1 2
2 4 3
4 2 0
0 5 4
YES
思路:本题初看似乎很复杂,设计那么多的边和三角形,但想想,可以将图形进行转换,尝试将多边形的每个三角形看成一个结点,有公共边的三角形所对应的顶点之间连一条边,则所给的图形可以看作是有n-2个结点,n-3条边的一个无向图G。显然,G构成一棵树T,把黑色三角形对应的结点看作树T的根,则树T最多有三棵子树。
接下来考虑必胜策略,显然,若要切掉根结点,则必须先将根的子树切到只剩一根。需要考虑的只是子树的结点个数,用非负整数(x,y,z)表示根的三棵子树的结点个数,不妨设x<=y<=z,则显然z>0。
(1)y=0,则x=0,为必胜状态;
(2)y>0,则最终结局必是(1,0,0),(0,1,0),(0,0,1)的一种;
显然,在(2)情况下,要想让先走的赢,x+y+z为奇数。
算法实现:主要的问题在于x,y,z的求取。由于多边形为顺时针编号,设黑三角形的编号为(i,j,k),假设满足i<j<k,则树T的三棵子树对应的多边形分别有j-i-1,k-j-1,n-(k-i-1)个顶点,也就会包含有j-i-1,k-j-1,n+i-k-1个三角形(结点),排序后,对应x,y,z。
代码:
int main()
{
while(cin>>n&&n)
{
cin>>i>>j>>k;
n-=3;
while(n--)
cin>>a>>b>>c;
Swap(i,j,k);//排序:i<j<k
x=j-i-1,y=k-j-1,z=n+i-k-1;
Swap(x,y,z);//排序:x<=y<=z
if(y==0||(x+y+z)&1)
printf("Yes\n");
else
printf("No\n");
}
}