poj 1029
请各位做POJ1029 False coin(http://poj.org/problem?id=1029),题意如下:
已知n个外观完全相同的硬币中,有且仅有一个假币,假币重量与真币不同,其余的真币重量都相同。给定n个硬币(编号从1到n),进行了k次称量,每次称量都在天平两端摆放了同样多的硬币,告诉你天平左边和右边的硬币编号,并告之称量结果(称量结果为“<”表示天平左轻右重,为“>”表示天平左重右轻,为“=”表示左右等重)。要求根据这k次天平比较状态判断出哪个硬币是假币。若可以判断出来则输出该硬币编号,否则输出0, 输入输出格式请参考原题页面。
要求使用“穷举各种假设,再验证”的方法,输入与输出必须严格按照题目给定格式,在线提交,只有提交结果返回Accept才算正确完成。
Sample Input
5 32 1 2 3 4<1 1 4=1 2 5=Sample Output3题意:已知n个外观完全相同的硬币中,有且仅有一个假币,假币重量与真币不同,其余的真币重量都相同。给定n个硬币(编号从1到n),进行了k次称量,每次称量都在天平两端摆放了同样多的硬币,告诉你天平左边和右边的硬币编号,并告之称量结果(称量结果为“<”表示天平左轻右重,为“>”表示天平左重右轻,为“=”表示左右等重)。要求根据这k次天平比较状态判断出哪个硬币是假币。若可以判断出来则输出该硬币编号,否则输出0。例如:输入如下5 3 (5表示有5个硬币,3表示称了3次,下面依次是每次称的结果)2 1 2 3 4 (2表示天平的左右两边分别放2个硬币,分别是1、2和3、4)< (左边<右边)1 1 4 (1表示天平的左右两边分别放1个硬币,分别是1和4)= (左边=右边)1 2 5 (1表示天平的两边分别放1个硬币,分别是2和5)= (左边=右边)思路:使用蛮力法。穷举1-n个硬币,分别判断是否是假币(即假设该硬币是假币,是否与已知的天平判断结果一致),试探时候也要穷举两种情况:重量轻了、重量重了。也就是说,要假设某个硬币是比真币轻/重的假币,是否会和k次称量结果的某一次产生矛盾。若全部试探完后发现:若按照假设的假币,发现假币的个数为1,则说明假币就是该硬币;否则说明假币可能超过2个,则说明不能判断到底假币是哪个。
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
using namespace std;
struct Node// 记录一次称量的状态和结果
{
int num;// 天平左右两端各有多少硬币
int* left;// 天平左边硬币的编号数组
int* right;// 天平右边硬币的编号数组
char result;// 称量结果
};
// 函数判断一次称量的状态和结果是否与假设的假币是否会产生矛盾
// 参数falseCoin表示假设的假币的编号
// 参数state表示某一次具体的称量的状态和结果
// 参数weight表示假设假币比真币重还是轻,true表示重,false表示轻
// 返回值为false表示存在矛盾,为true表示不存在矛盾
bool JudgeOnce(int falseCoin, const Node& state, bool weight)
{
switch (state.result)// 注意假币有且仅有一枚
{
case '<':// 比较结果左轻右重
if (weight)// 假设假币更重,则假币在右边
{
for (int i = 0; i != state.num; i++)// 遍历天平右边的硬币
{
if (state.right[i] == falseCoin)// 天平右边某块硬币就是我们假设的假币
{
return true;// 假设的假币和这一次称量没有矛盾
}
}
return false;// 假设的假币和这一次称量结果存在矛盾
}
else // 假设假币更轻,则假币在左边
{
for (int i = 0; i != state.num; i++)// 遍历天平左边的硬币
{
if (state.left[i] == falseCoin)// 天平左边某块硬币就是我们假设的假币
{
return true;// 假设的假币和这一次称量没有矛盾
}
}
return false;// 假设的假币和这一次称量结果存在矛盾
}
break;
case '>': // 比较结果左重右轻
if (weight) // 假设假币更重,那么假币在左边
{
for (int i = 0; i != state.num; i++)// 遍历天平左边的硬币
{
if (state.left[i] == falseCoin)// 天平左边某块硬币就是我们假设的假币
{
return true;// 假设的假币和这一次称量没有矛盾
}
}
return false;// 假设的假币和这一次称量结果存在矛盾
}
else // 假设假币更轻,那么假币在右边
{
for (int i = 0; i != state.num; i++)// 遍历天平右边的硬币
{
if (state.right[i] == falseCoin)// 天平右边某块硬币就是我们假设的假币
{
return true;// 假设的假币和这一次称量没有矛盾
}
}
return false;// 假设的假币和这一次称量结果存在矛盾
}
break;
default:// 左右两边相等,假币没有出现在天平中
for (int i = 0; i != state.num; i++)// 遍历天平右边的硬币
{
if (state.right[i] == falseCoin)// 天平右边某块硬币就是我们假设的假币
{
return false;// 此时天平不应该是平衡的,矛盾
}
}
for (int i = 0; i != state.num; i++)// 遍历天平左边的硬币
{
if (state.left[i] == falseCoin)// 天平左边某块硬币就是我们假设的假币
{
return false;// 此时天平不应该是平衡的,矛盾
}
}
return true;// 假设的假币不在天平中,和这一次称量结果没有矛盾
break;
}
}
// 检测所有的称量,找到唯一的假币
// 参数n表示有n个硬币,编号为1-n
// 参数m表示有m次称量
// 参数states表示每次称量的情况构成的数组
// 参数ans表示找到的假币编号,是引用参数
// 返回值表示判断结果,如果为0,表示没有假币,如果为1,表示有唯一的假币,如果为2,表示假币不止一枚
int Process(int n, int m, Node* states, int& ans)
{
int falseCoinCount = 0;// 目前统计出的假币个数
for (int i = 1; i <= n; i++) // 遍历所有的硬币,假设硬币i是假币
{
bool flag = true;// flag表示硬币i是假币,且比真币轻这个猜想是否成立
for (int j = 0; j < m; j++)// 遍历所有的称量情况
{
if (!JudgeOnce(i, states[j], false))// 当前假设与第j次称量的情况矛盾
{
flag = false;
break;// 假设已经不成立,再假设硬币i+1是假币
}
}
if (flag)// 硬币i是假币,且比真币轻这个猜想是成立的
{
falseCoinCount++;// 已经找到的假币个数加1
ans = i;// 硬币i是假币,用ans记录
if (falseCoinCount > 1)// 假币不止一枚
{
return falseCoinCount;
}
}
else// 硬币i是假币,且比真币轻这个猜想不成立的
{
flag = true;// flag表示硬币i是假币,且比真币重这个猜想是否成立
for (int j = 0; j < m; j++)// 遍历所有的称量情况
{
if (!JudgeOnce(i, states[j], true))// 当前假设与第j次称量的情况矛盾
{
flag = false;
break;// 假设已经不成立,再假设硬币i+1是假币
}
}
if (flag)// 硬币i是假币,且比真重轻这个猜想是成立的
{
falseCoinCount++;// 已经找到的假币个数加1
ans = i;// 硬币i是假币,用ans记录
if (falseCoinCount > 1)// 假币不止一枚
{
return falseCoinCount;
}
}
}
}
return falseCoinCount;
}
int main()
{
//freopen("coin.in", "r", stdin);
int n = 0;
int m = 0;
while (scanf("%d %d", &n, &m) != EOF && n > 0 && m > 0)
{
Node* states = new Node[m];
for (int i = 0; i < m; i++)
{
//输入天平测试状态和结果
scanf("%d", &states[i].num);
states[i].left = new int[states[i].num];
for (int j = 0; j < states[i].num; j++)
{
scanf("%d", &states[i].left[j]);
}
states[i].right = new int[states[i].num];
for (int j = 0; j < states[i].num; j++)
{
scanf("%d", &states[i].right[j]);
}
getchar();
states[i].result = getchar();
}
int ans = -1;
int falseCoinCount = Process(n, m, states, ans);
if (falseCoinCount == 1)
{
printf("%d\n", ans);
}
else
{
printf("0\n");
}
for (int i = 0; i < m; i++)
{
delete[] states[i].left;
delete[] states[i].right;
}
delete[] states;
}
return 0;
}
POJ1029假币问题求解思路
博客介绍了POJ1029 False coin问题,已知n个硬币中有一个假币,通过k次天平称量判断假币编号。给出了具体输入输出示例,还阐述了解题思路,使用蛮力法穷举1 - n个硬币,分别假设其为轻或重的假币,根据是否与称量结果矛盾来判断。
1192

被折叠的 条评论
为什么被折叠?



