链接:http://poj.org/problem?id=1029
有个类似的题是在之前学枚举的时候遇到过,之前的那个例子要简单些。但原理是一样的。所以拿来这个题借鉴一下。
对于假币,存在两种情况:比真币重,或者,比真币轻。又总共有n个硬币,所以有2*n那种情况。
对于每一个硬币,要满足题中m个比对结果,则这个硬币为假硬币。
咳咳。。。当然对于一般的数据,上面的方法是正确的。但对于某些特殊的数据还是要进行判断。
这里,我给两组数据:
5 2
1 1 4
=
1 2 5
=
answer:3
6 2
1 1 4
=
1 2 5
=
answer:0
在第一个例子中,我们可以发现,硬币3是满足所有的比对结果的,所以3是假硬币。
而对于第二个例子,我们又可以发现,硬币3和6均满足所有的比对结果。而这时,结果就有可能不对,所以我在这里设置了temp变量,来排除这种情况。
还有一个例子:
2 1
1 1 2
>
answer:0
这个代码刚写好的时候有很多bug,所以修修补补之后,在最后的判断条件上有点乱。主要就是用flag变量来记录不同的情况来进行判断。
#include<stdio.h>
#include<string.h>
int left[105][505],right[105][505];
//left[i][j]用于存储左边天平的硬币
//right[i][j]用于存储右边天平的硬币
char res[105][1];
//res[i][j]用来存储每次比对的结果,即“>”、“<”、“=”
int n,k,p;
int find(int *seq,int x)//查找x是否存在数列seq中
{
int i;
for(i=0;i<505;i++)
if(seq[i]==x)
return 1;
return 0;
}
int IsLight(int x)//如果假币比真币轻
{
int i;
for(i=0;i<k;i++)
switch(res[i][0])
{
case '<':if(!find(right[i],x))//对于“>”,则假币必定存在于右盘
return 0;
break;
case '>':if(!find(left[i],x))//对于“<”,则假币必定存在于左盘
return 0;
break;
case '=':if(find(left[i],x)||find(right[i],x))//对于“=”,则假币不存在任何一个盘
return 0;
break;
}
return 1;
}
int IsHeavy(int x)//如果假币比真币重,同上
{
int i;
for(i=0;i<k;i++)
switch(res[i][0])
{
case '<':if(!find(left[i],x))
return 0;
break;
case '>':if(!find(right[i],x))
return 0;
break;
case '=':if(find(left[i],x)||find(right[i],x))
return 0;
break;
}
return 1;
}
int main()
{
int i,j;
int pos1,pos2,flag1,flag2,ans,temp;
while(scanf("%d%d",&n,&k)!=EOF)
{
flag1=0;
flag2=0;
ans=0;
pos1=0;
pos2=0;
temp=0;
memset(left,0,sizeof(left));
memset(right,0,sizeof(right));
for(i=0;i<k;i++)
{
scanf("%d",&p);
for(j=0;j<p;j++)
scanf("%d",&left[i][j]);
for(j=0;j<p;j++)
scanf("%d",&right[i][j]);
getchar();
scanf("%c",&res[i][0]);
}
for(i=1;i<=n;i++)//枚举每一个硬币
//此题中假币只有一个,所以结果唯一
{
if(IsLight(i))
{
pos1=i;
flag1++;
}
if(IsHeavy(i))
{
pos2=i;
flag2++;
}
if((flag1==flag2)&&flag1&&flag2&&pos1==pos2&&pos1!=temp)
{
ans++;
temp=pos1;
}
}
if((flag1==1)&&!flag2)//一般的数据,只有一个比真币轻的假硬币,满足所有比对结果
printf("%d\n",pos1);
if(!flag1&&(flag2==1))//一般的数据,只有一个比真币重的假硬币,满足所有比对结果
printf("%d\n",pos2);
if((flag1==flag2)&&flag1&&flag2)//比对的所有结果是“等号”
{
if(pos1==pos2&&ans==1)//同一个硬币,且只有一个,即ans==1(针对以上两个例子)
printf("%d\n",pos1);
else
printf("%d\n",0);//否则为0,如第二个例子和第三个例子
}
if((!flag1&&!flag2)||((flag1>1||flag2>1)&&(flag1!=flag2)))
//flag1=0&&flag2=0,没有一个满足所有比对结果的硬币
//flag1>1||flag2>1且flag1!=flag2,有多个满足所有结果的硬币,即结果不唯一,不满足题意
printf("%d\n",0);
}
return 0;
}