POJ1029 寻找假币(穷举法)

cuicuiv—POJ刷题

点击此处看原题---->POJ1029寻找假币

描述
The "Gold Bar"bank received information from reliable sources that in their last group of N coins exactly one coin is false and differs in weight from other coins (while all other coins are equal in weight). After the economic crisis they have only a simple balance available (like one in the picture). Using this balance, one is able to determine if the weight of objects in the left pan is less than, greater than, or equal to the weight of objects in the right pan.
In order to detect the false coin the bank employees numbered all coins by the integers from 1 to N, thus assigning each coin a unique integer identifier. After that they began to weight various groups of coins by placing equal numbers of coins in the left pan and in the right pan. The identifiers of coins and the results of the weightings were carefully recorded.
You are to write a program that will help the bank employees to determine the identifier of the false coin using the results of these weightings.

**概述:**有一组N个硬币中有一个假币,其重量与其他硬币不同。有一个天平,可以确定左边物体的重量是否小于,大于或等于右边物体的重量。需要你编写一个程序确定假币的标识符。(设硬币已从从1-N排序)

Input
The first line of the input file contains two integers N and K, separated by spaces, where N is the number of coins (2<=N<=1000 ) and K is the number of weightings fulfilled (1<=K<=100). The following 2K lines describe all weightings. Two consecutive lines describe each weighting. The first of them starts with a number Pi (1<=Pi<=N/2), representing the number of coins placed in the left and in the right pans, followed by Pi identifiers of coins placed in the left pan and Pi identifiers of coins placed in the right pan. All numbers are separated by spaces. The second line contains one of the following characters: ‘<’, ‘>’, or ‘=’. It represents the result of the weighting:
‘<’ means that the weight of coins in the left pan is less than the weight of coins in the right pan,
‘>’ means that the weight of coins in the left pan is greater than the weight of coins in the right pan,
‘=’ means that the weight of coins in the left pan is equal to the weight of coins in the right pan.

概述:
第一行输入:N(硬币个数) K(称重的次数) 如n=5,k=1
第二行输入:2 1 2 3 4 (2表示天平的左右两边分别放2个硬币,分别是1、2和3、4)
第三行输入:< (左边<右边)

Output
Write to the output file the identifier of the false coin or 0, if it cannot be found by the results of the given weightings.

**概述:**结果输出假币的序号,若找不到则输出0

以下为C实现代码:

#include <stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
#define Max 1000
#define Maxx 100
using namespace std;

struct Node{                //天平结构体
        int num;            //硬币编号
        int left[Max/2];    //左盘
        int right[Max/2];   //右盘
        char result;        //< > = 三种结果
}node[Maxx];

据题意构造天平结构体 node[x]分别记录第x次称重内容


int n,m;//硬币个数 天平测量数
int rpoint;//结果
//函数判断一次假设与结果是否矛盾
//fnode创建一个假设对象
//bool weight表示假设假币比真币重还是轻 true表示重 false表示轻
//falaseCoin 表示假币
bool Judgeonce(int falseCoin,struct Node fnode,bool weight)
{   switch(fnode.result){//< > = 三种情况
case '<':
    if(!weight){//轻 符合< 则假币在左盘
        for(int i=0;i<=fnode.num;i++)
            if(fnode.left[i]==falseCoin)
                return true;//假设没矛盾
            return false;//假设与称量结果存在矛盾
    }
    else//重 假币在右边
    {
        for(int i=0;i<=fnode.num;i++)
        if(fnode.right[i]==falseCoin)
            return true;
        return false;
    }
    break;
    //以下两种情况类似上述情况
case'>':
    if(weight)
    {
        for(int i=0;i<=fnode.num;i++)
            if(fnode.left[i]==falseCoin)
            return true;
        return false;
    }
    else
    {
        for(int i=0;i<=fnode.num;i++)
            if(fnode.right[i]==falseCoin)
            return true;
        return false;
    }
    break;
default:
    for(int i=0;i<=fnode.num;i++)
        {
        if(fnode.right[i]==falseCoin)
        return false;
        }
    for(int i=0;i<=fnode.num;i++)
        {
        if(fnode.left[i]==falseCoin)
        return false;
        }
        return true;
        break;
           }
}


int main(){
    scanf("%d%d",&n,&m);
    int p=1; //从node[1]开始记录称重次数 
    while(n>0&&m>0)//
    {
        for(int i=1;i<=m;i++)//循环输入m次
        {
            scanf("%d",&node[p].num);//输入左右盘的币
            for(int j=1;j<=node[p].num;j++)
                scanf("%d",&node[p].left[j]);//左盘编号
            for(int j=1;j<=node[p].num;j++)
                scanf("%d",&node[p].right[j]);//右盘编号
            getchar();
            node[p++].result=getchar();
        }


    int falsecount=0;//假币计数
    for(int i=1;i<=n;i++){
        bool trag=true;//trag表示硬币i是假币
        for(int j=1;j<p;j++){//测试为轻的情况
            if(!Judgeonce(i,node[j],false)){
                    trag=false;
                    break;

            }
        }
        if(trag){
            falsecount++;
            if(falsecount>1){
                printf("0\n");
                return 0;
            }
            rpoint=i;

        }
        else{
            trag=true;
            for(int j=1;j<p;j++){
                if(!Judgeonce(i,node[j],true)){
                    trag=false;
                    break;
                }
            }
            if(trag){
                falsecount++;
                if(falsecount>1){
                    printf("0\n");
                    return 0;
                }
                rpoint=i;
            }
        }

    }
printf("%d\n",rpoint);
return 0;


    }
    }

总结:

  1. 巧用bool型函数,嵌套使用,利用反证思维。即假设正确与实际结果出现矛盾则结果在假设的反方。
  2. 本题采用穷举法求解,例出了所有可能结果,遍历求解了所有情况。代码量比较多,但思路清晰便于理解,比较适合初学者解题。
  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值