题目:有N个硬币,里面有一个硬币是坏的,现在称了M次(称两边放数量一样的硬币)并把结果作为输入,根据称的结果判断第几号硬币是坏的。
例如:输入如下
5 3 (5表示有5个硬币,3表示称了3次,下面依次是每次称的结果)
2 1 2 3 4 (2表示称的两边分别放两个硬币,分别是1、2和3、4)
< (1+2<3+4)
1 1 4 (1表示称的两边分别放一个硬币,分别是1和4)
= (1=4)
1 2 5 (1表示称的两边分别放一个硬币,分别是2和5)
= (2=5)
按照上面的题意,我的最初想法应该是这样的:如果称的结果是不等号(即大于或者小于),那么此次被称的硬币中肯定有坏的硬币;如果称的结果是等号,那么此次被称的硬币肯定是好的硬币。
编程:创建一个bitset,对每次称的硬币结果进行判断:
(1)如果称的结果为等号,则将bitset相应的位置1表示,表示此位置的硬币肯定是真的;
(2)如果称的结果是不等号,则和bitset进行合并,即如果某个硬币上次是被称不等号,而此次又在又被称不等号,则保留bitset的0位,否则置1表示这个硬币不是坏的。简而言之,就是某个硬币和不等号出现的次数相等则被认为是坏硬币。
(3)坏硬币的数量大于1,则表示判断不出坏硬币,输出0,否则输出相应的硬币号。
#include<iostream>
#include<bitset>
#include<cstdlib>
using namespace std;
const int MAX = 1001;
typedef pair<bool,int>result;
class falseCoin{
friend istream& operator>>(istream& is,falseCoin& fcoin)
{
is>>fcoin.coins>>fcoin.cmps;
return is;
}
public:
result solution(void)
{
bitset<MAX> bitmap;//为硬币建立一个位图
int weightings;//称每边包含的硬币数据
int *tmp = new int[coins];//保存称两边的硬币序列号
memset(tmp,0,coins);
int i = 0,j;//循环变量
char ch;//每次比较的结果
while(cmps--){
cin>>weightings;
while(i<2*weightings){
cin>>tmp[i++];
}
cin>>ch;
if('<'== ch||'>'==ch){
for(i=0;i<coins;i++){
if(!bitmap.test(i)){
bitmap.set(i);
for(j=0;j<2*weightings;j++)
if(i==tmp[j]-1)bitmap.reset(i);
}
}
}
else{
for(i=0;i<2*weightings;i++)
bitmap.set(tmp[i]-1);//置位表示该硬币一定是真硬币
}
i = 0;
}
int count=0;//计算0的个数,即假硬币的个数
int index;
for(i=0;i<coins;i++){
if(!bitmap.test(i)){
count++;
index = i;
}
}
delete tmp;
if(1==count)return make_pair(true,index+1);
else return make_pair(false,0);
}
private:
int coins;//总的硬币数
int cmps;//比较次数
};
int main()
{
falseCoin poj1029;
cin>>poj1029;
cout<<poj1029.solution().second<<endl;
system("pause");
return 0;
}
最终,WA了,后来我发现,如果称的结果是这样的话,上面程序判断出为2,但其实没有答案。
3 2
1<2
2<3
上面这组测试数据,其实有2个错误的硬币或者全错。后来发现我个程序只能在只有一个坏硬币的情况下,才能得到正确答案。
网友 Slyar Home http://www.slyar.com/blog/poj-1029-cpp.html
思路就是假币应该在每个不等式中都出现,最后只要看哪个硬币出现的次数和不等式出现的次数相同,如果这个硬币唯一,那它就是确认的假币。
#include <iostream>
#include <string>
using namespace std;
const int MAX = 1001;
int main()
{
int n, k, p, total = 0;
char sign;
/* 记录原始数据 */
int t[MAX] = {0};
/* 标记硬币真假 */
int r[MAX] = {0};
/* 记录硬币重量 */
int w[MAX] = {0};
cin >> n >> k;
while (k--)
{
/* 读入原始数据 */
cin >> p;
for (int i = 0; i < 2 * p; i++)
{
cin >> t[i];
}
cin >> sign;
/* 标记肯定为真的硬币 */
if (sign == '=')
{
for (int i = 0; i < 2 * p; i++)
{
r[t[i]] = 1;
}
}
/* 左轻右重 */
else if (sign == '<')
{
total++;
for (int i = 0; i < p; i++)
{
w[t[i]]--;
}
for (int i = p; i < 2 * p; i++)
{
w[t[i]]++;
}
}
/* 左重右轻 */
else if (sign == '>')
{
total++;
for (int i = 0; i < p; i++)
{
w[t[i]]++;
}
for (int i = p; i < 2 * p; i++)
{
w[t[i]]--;
}
}
}
/* 假币在不等式中每次都应该出现 */
int count = 0, pos = 0;
for (int i = 1; i <= n; i++)
{
if (r[i])
{
continue;
}
/* 找出每次都出现的"假币" */
if (w[i] == total || w[i] == - total)
{
count++;
pos = i;
}
}
/* 假币唯一则输出 */
if (count != 1)
{
cout << 0 << endl;
}
else
{
cout << pos << endl;
}
//system("pause");
return 0;
}
想法一样,编程相差略大,恩,学习了。