剪刀石头布游戏
2006 年百度之星程序设计大赛初赛题目 4
N 个小孩正在和你玩一种剪刀石头布游戏。 N 个小孩中有一个是裁判,其余小孩分成三组(不排除某些组没有任何成员的可能性),但是你不知道谁是裁判,也不知道小孩们的分组情况。然后,小孩们开始玩剪刀石头布游戏,一共玩 M 次,每次任意选择两个小孩进行一轮,你会被告知结果,即两个小孩的胜负情况,然而你不会得知小孩具体出的是剪刀、石头还是布。已知各组的小孩分别只会出一种手势(因而同一组的两个小孩总会是和局),而裁判则每次都会随便选择出一种手势,因此没有人会知道裁判到底会出什么。请你在 M 次剪刀石头布游戏结束后,猜猜谁是裁判。如果你能猜出谁是裁判,请说明最早在第几次游戏结束后你就能够确定谁是裁判。
输入格式:
输入文件包含多组测试数据。每组测试数据第一行为两个整数 N 和 M ( 1 ≤ N ≤ 500 , 0 ≤ M ≤ 2000 ),分别为小孩的个数和剪刀石头布游戏进行的次数。接下来 M 行,每行两个整数且中间以一个符号隔开。两个整数分别为进行游戏的两个小孩各自的编号,为小于 N 的非负整数。符号的可能值为“ = ”、“ > ”和“ < ”,分别表示和局、第一个小孩胜和第二个小孩胜三种情况。
输出格式:
每组测试数据输出一行,若能猜出谁是裁判,则输出身为裁判的小孩的编号,并输出在第几次游戏结束后就能够确定谁是裁判。如果无法确定谁是裁判,或者发现剪刀石头布游戏的胜负情况不合理(即无论谁是裁判都会出现矛盾),则输出相应的信息。具体输出格式请参考输出样例。
输入样例
3 3
0<1
1<2
2<0
3 5
0<1
0>1
1<2
1>2
0<2
4 4
0<1
0>1
2<3
2>3
1 0
输出样例 【剪刀石头布游戏】
Can not determine
Player 1 can be determined to be the judge after 4 lines
Impossible
Player 0 can be determined to be the judge after 0 lines
说明:
共有 5 个测试数据集,每个测试数据集为一个输入文件,包含多组测试数据。每个测试数据集从易到难分别为 5 、 10 、 15 、 30 和 40 分,对每个测试数据集分别执行一次程序,每次必须在运行时限 3 秒内结束程序并输出正确的答案才能得分。
所有数据均从标准输入设备( stdin/cin )读入,并写出到标准输出设备 ( stdout/cout )中。
五个测试数据集中输入 N 分别不大于 20 、 50 、 100 、 200 和 500 ,各有 10 组测试数据。
//说明:最低四位表示child分组状态,0:未分组,1/2/3:三组,4:裁判
//次低四位表示child检查状态,0:在以前数据中未出现,
//1:已出现一次,第二次出现即可进行检查判断,2:检查后可能是裁判,3:检查后不可能是裁判
//
using System;
using System.Collections.Generic;
using System.Collections;
using System.Collections.Specialized;
using System.Threading;
using System.IO;
public class childclqr
{
int n;
int m;
int[,] data;
int[] child;
int[] maybecps;
int cpps=-1;
string result;
public string Result
{ get { done();
return result;
} }
public childclqr(int n,int m,string[]ss)
{
this.n = n;
this.m = m;
data=https://www.it610.com/article/new int[m,4];
child=new int[n];
maybecps=new int[n+1];
for (int k = 0;
k < m;
k++)
{
data[k, 0] = 0;
sws(ss[k],k);
}
}
public childclqr(string infile,string outfile)
{
FileStream fs = new FileStream(infile,FileMode.Open,FileAccess.Read);
StreamReader sr = new StreamReader(fs);
FileStream fo = new FileStream(outfile,FileMode.Create,FileAccess.Write);
StreamWriter sw = new StreamWriter(fo);
string s = sr.ReadLine();
while(s!=null)
{
string[] t = s.Split();
n = int.Parse(t[0]);
m = int.Parse(t[1]);
t=new string[m];
for (int j = 0;
j < m;
j++)
t[j] = sr.ReadLine();
childclqr c = new childclqr(n,m,t);
sw.WriteLine(c.Result);
s = sr.ReadLine();
}
sr.Close();
sw.Close();
}
void sws(string s,int n)
{
data[n, 1] = 0;
data[n, 3] = 0;
int k = 0;
while (s[k] <='9' && s[k] >= '0')
data[n, 1] = 10 * data[n, 1] + s[k++] - '0';
data[n, 2] = s[k++];
while(k';
}
}
bool maybecp(int c,int k)//在前k组data中假设c为cp,是否没有矛盾
{
int j=0;
for (;
j < n;
j++)//清除分组情况
child[j] &= 0xf0;
int left = k + 1,begin=0;
for (j = 0;
j <= k;
j++)//有c的data置1,其余置0
{
if (data[j, 1] == c || data[j, 3] == c)
{ data[j, 0] = 1;
left--;
}
else
data[j, 0] = 0;
}
child[c] |= 4;
//c置为cp
while (left > 1)//left为剩余data,剩余至少两条时进行计算
{
while (data[begin, 0] == 1) begin++;
//找到第一个未计算的data
child[data[begin, 1]] += 1;
//假定第一个child的分组
for (j = begin;
j <=k;
j++)
if(data[j,0]==0)
{
int za = child[data[j, 1]]%16, zb = child[data[j, 3]]%16;
int sign = data[j, 2];
data[j, 0] = 1;
left--;
if (za > 0 && zb > 0)//若双方已分组,则判断是否有矛盾,有则返回错误
{ if ((sign == '=' && za != zb) || (za != (zb + 1) % 3 + 1))return false;
}
//一方已分组,一方未知,确定未知方的分组,并返回begin重新计算
else if (za == 0 && zb > 0)
{
if (sign == '=') child[data[j, 1]] += zb;
else child[data[j, 1]] += (zb + 1) % 3 + 1;
j = begin - 1;
}
else if (za > 0 && zb == 0)
{
if (sign == '=') child[data[j, 3]] += za;
else child[data[j, 3]] += za % 3 + 1;
j = begin - 1;
}
else//双方都未分组,原begin已计算,则重定为当前值
{ data[j, 0] = 0;
left++;
if (data[begin, 0] == 1)begin = j;
}
}
}
return true;
//没有矛盾,返回true
}
void readytomaybe(int b,int k)
{
if (child[b] >> 4 == 1)
{
if (maybecp(b, k))
{
child[b] += 0x10;
maybecps[++maybecps[0]] = b;
if (maybecps[0] == 1)
cpps = k;
return;
}
else
{
child[b] += 0x20;
return;
}
}
}
void toleft(int mlen)
{
if (mlen!=maybecps[0]&&maybecps[0] > 0)
{
int r = 1;
while (maybecps[r] != -1) r++;
int p = r+1;
while (r<=maybecps[0])
{
while(maybecps[p]==-1)p++;
maybecps[r++] = maybecps[p];
maybecps[p++]=-1;
}
}
}
void anay(int k)
{
int a=data[k,1];
int b = data[k, 3];
if (child[a] >> 4 == 0 || child[b] >> 4 == 0)//若ab中有一个以前未出现
{
int t = a;
a = child[a] >> 4 == 0 ? a : b;
b = t != a ? t : b;
child[a] |= 0x10;
//将a设为ready
if (child[b] >> 4 == 0)
{ child[b] |= 0x10;
return;
}
else
readytomaybe(b,k);
//若b为ready则进行检查
return;
}
else
{
int t=-1,mlen = maybecps[0];
if (mlen == 1) t = maybecps[1];
for (int j = 1;
j <=mlen;
j++)//检查maybecps中的每个成员
if (!maybecp(maybecps[j], k))
{
child[maybecps[j]] += 0x10;
maybecps[j] = -1;
maybecps[0]--;
}
toleft(mlen);
//调整maybecps
readytomaybe(a,k);
readytomaybe(b,k);
if (maybecps[0] == 1 && t != maybecps[1])//若有变化,记下cpps
cpps = k;
}
}
void done()
{
if (m == 0)
{ result = "Player 0 can be determined to be the judge after 0 lines ";
return;
}
for (int k = 0;
k < m;
k++)
anay(k);
if (maybecps[0] == 0)
result = "Impossible !";
else if (maybecps[0] == 1)
result = string.Format("Child {0} is judge,he can be judged after {1} lines",maybecps[1],cpps+1);
else result = "Can not determine!";
}
}
推荐阅读
- 石头巷;名垂青史的廉政教材
- 远古科技之不起眼的石头
- 投石机可连续抛射石头【Algodoo|投石机可连续抛射石头【Algodoo | 物理模拟】
- 小石头奇遇记(二)
- D016+8组田心+《吉田医生哈佛求学记》-优先做大石头事件
- 三行情书|三行情书|夙求
- 石头画
- 相同的石头(一)
- 你失恋的之后干过什么事(有人把日子过荒废了,有人把石头滴穿了)
- 2006 年百度之星程序设计大赛初赛题目 4 剪刀石头布