/* 枚举罪犯和星期几,那么所有人说的话是真是假一目了然。 首先一个人不能既说真话又说假话。 即: I am guilty. I am not guilty. 因为非真即假,所以直接判断impossible. map<string,int>表示名字对应的id name[i]表示id为i的人对应的人名。 kp[i][j]表示第i个人认为第j个人是不是罪犯。0/-1/1,表示不是,没说,是 kd[i][j]表示第i个人认为今天是星期j么?0/-1/1表示 不认为、没说、认为 impossible的情况之一即kp[i][j]=1后又要赋值为 kp[i][j]=0; 假设罪犯是t(id),今天是d;//现在已经没有人既说真话又说假话了。 现在人有三类: 说真话 说假话 说废话 如何判断一个人说真话还是说假话。 假设 Amy: ①I am guilty. (如果Amy不是t,那么这人说假话;如果Amy是t,那么这个人一定说真话) ②I am not guilty. (如果他是t,那么这人说假话;如果不是t,那么它一定说真话) ③XXX is guilty. (XXX是t,真话;XXX不是t,假话) ④XXX is not guilty. (XXX是t,假话;XXX不是t,真话) ⑤Today is x (x是d,真话;x不是d,假话)。 所以,一个人只要不说废话,那么他说真话还是说假话都知道了 say[i]=0/-1/1表示id为i的人说假话,不确定,说真话 若一个人说的是假话,那么他说的假话的反面就是真话。 下面的句子是可以通过这个人说的是假话判断出来的。 ①他不是罪犯 ②他是罪犯 ③XXX 不是罪犯 ④XXX 是罪犯 这时需要另辟数组来标记。 p[i]=0/-1/1分别表示这个人不是罪犯、不确定、是罪犯。 d[i]=0/-1/1分别表示今天不是星期i、不确定是不是星期i、今天是星期i。 这时矛盾出现了 甲: A is guilty. t is not guilty. 乙: A is not guilty. t is not guilty. 此时甲、乙二人都不认为t是罪犯,那么他们说的都是假话了 根据甲来说:A 应该不是罪犯。 根据乙来说:A 应该是罪犯。 出现了矛盾,这个情况应该pass了。 即p[i]赋值为0后,又要被赋值为1。d数组同样。 所以p[]、d[]数组只能从不确定状态赋值为确定状态,不能从一个 确定状态标记为另一个确定状态。 如果说谎话的人<=n&&说谎的人+说废话的人>=n,那么满足始终有n个人说假话了。 在看p[i]数组,如果有人标记了不确定是不是罪犯,那么这个情况就是不确定罪犯了。 所以最后 1)若唯一能确定罪犯,输出。 2)不能唯一确定,有多解的情况 cannot determine。 3)所有举例的情况都有矛盾,都被pass了,impossible.
下面的代码windows下是A的...洛谷A不了....占个坑。
#include<iostream> #include<map> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int m,n,p,ans; int say[22]; int kp[22][22],kd[22][10]; string name[22]; string a[22],b[22],c[22]; map<string,int>k; void read() { for(int i=1;i<=m;i++) { string s; cin>>s; name[i]=s; s+=":"; k[s]=i; } // char ch=getchar(); // while(ch==10)ch=getchar();getchar(); for(int i=1;i<=p;i++) { cin>>a[i]>>b[i]; if(b[i]!="Today"&&c[i]!=" is guilty."&&c[i]!=" is not guilty.")b[i]+=":";//*** getline(cin,c[i]); } } void pre_deal() { int flag=0; memset(kp,-1,sizeof(kp)); memset(kd,-1,sizeof(kd)); for(int i=1;i<=p;i++) { int id=k[a[i]]; if(c[i]==" am guilty.") {if(!kp[id][id]) flag=1;else kp[id][id]=1;} if(c[i]==" am not guilty."){if(kp[id][id]==1) flag=1;else kp[id][id]=0;} if(c[i]==" is guilty.") {int h=k[b[i]];if(!kp[id][h]) flag=1;else kp[id][h]=1;} if(c[i]==" is not guilty."){int h=k[b[i]];if(kp[id][h]==1) flag=1;else kp[id][h]=0;} if(b[i]=="Today") { if(c[i]==" is Monday.") kd[id][1]=1; if(c[i]==" is Tuesday.") kd[id][2]=1; if(c[i]==" is Wednesday.") kd[id][3]=1; if(c[i]==" is Thursday.") kd[id][4]=1; if(c[i]==" is Friday.") kd[id][5]=1; if(c[i]==" is Saturday.") kd[id][6]=1; if(c[i]==" is Sunday.") kd[id][7]=1; } if(flag){printf("Impossible ");exit(0);} //*** } } bool check(int x,int y) { memset(say,-1,sizeof(say)); for(int i=1;i<=m;i++) { for(int j=1;j<=m;j++) { if((kp[i][j]==1&&j!=x)||(kp[i][j]==0&&j==x)) { if(say[i]==1) return false; say[i]=0; } if((kp[i][j]==1&&j==x)||(kp[i][j]==0&&j!=x)) { if(say[i]==0) return false; say[i]=true; } } for(int q=1;q<=7;q++) { if(kd[i][q]==1&&q!=y) { if(say[i]==1) return false; say[i]=0; } if(kd[i][q]==1&&q==y) { if(say[i]==0) return false; say[i]=true; } } } return true; } int main() { scanf("%d%d%d",&m,&n,&p);//m同学数,n始终说谎的人数,p为证言总数。 read(); pre_deal(); for(int i=1;i<=m;i++) { for(int j=1;j<=7;j++) { int saylie=0,notjudge=0; if(check(i,j)) { for(int p=1;p<=m;p++) { if(say[p]==-1) notjudge++; if(say[p]==0) saylie++; } if(saylie<=n&¬judge+saylie>=n) { if(ans&&i!=ans) { printf("Cannot Determine "); exit(0); } ans=i; } } } } if(ans) cout<<name[ans]<<endl; else printf("Impossible "); return 0; }