poj1029 False coin

链接: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;
}


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值