POJ1013 Counterfeit Dollar 解题报告

题目描述

http://poj.org/problem?id=1013

有12枚硬币(标记为A-L),其中有1枚是假币,但不知道假币比真币更轻或更重。Sally借助于天平,设计出一种方案,可以恰好三次测量出谁是假币、比真币更轻或更重。要求你帮助Sally,根据她的测量数据,计算出谁是假币、比真币更轻还是更重。例如一组测量数据为:

ABCD EFGH even

ABCI EFJK up

ABIJ EFGH even

注意:天平左右的硬币数量总是相等的。

可以计算得出K是假币,且比真币更轻。

分析

解决这道题的关键是抓住以下几个关键点:

(1)假币只有一个,因此在不平衡的测量中,假币一定会出现。记录硬币出现在不平衡测量中的次数,是判断假币的一个条件。但仅用这个条件是不够的,比如:

A B up

CD AB up

C D even

在这个例子中,A和B出现在不平衡测量中的次数相等,都是2,因此还需考虑第二点。

(2)假币在测量中表现是一致的,假如假币比真币更轻,那么它在不平衡测量中一定总在up的一边。所以,凡是在不平衡测量里,时而在up的一边,时而在down的一边,如上例中的A,则说明其对测量的失衡没有决定性作用,则一定是真币,应该将它标注出来。

(3)出现在平衡测量中的硬币全是真币,将它们标注出来。

算法思路

定义COIN结构,如下:

struc COIN

{

    bool appear;

    int type;

    int count;
};

其中,appear标记是否出现在三次测量中,因为并非所有硬币都参与测量;type表示硬币的类型,初始为UNDEFINED,确定为真币则为DOLLAR,若非真币出现在up一边则为LIGHT,否则为HEAVY;count表示硬币出现在不平衡测量中的次数。

算法分为三步:

Step 1:初始化COIN数组,为本轮计算做好准备。

Step 2:根据输入的测量数据,更新COIN数组。

Step 3:扫描COIN数组,找到假币,并将其信息打印出来。

代码

// 1013.cpp
// 2012-12-27 by btwsmile
#include <stdio.h>
#include <string.h>
// define
#define UNDEFINED -1
#define LIGHT	   0
#define DOLLAR	   1
#define HEAVY	   2
#define N 12
// struct COIN
struct COIN
{
	bool appear;
	int type;
	int count;
};
// functions
// prepare - reset coin[]
void prepare(COIN*);
// update - update coin[]
void update(COIN*, char*, char*, char*);
// search - find Counterfeit in coin[]
int search(COIN*);
// entry
int main()
{
	COIN coin[N];
	char szLeft[10];
	char szRight[10];
	char szRelation[10];
	int n;
	scanf("%d", &n);
	for(int i = 0; i < n; ++i)
	{
		prepare(coin);
		// scanf & update
		for(int j = 0; j < 3; ++j)
		{
			scanf("%s %s %s", szLeft, szRight, szRelation);
			update(coin, szLeft, szRight, szRelation);
		}
		// find Counterfeit
		int iCounterfeit = search(coin);
		// print
		if(iCounterfeit > -1)
		{
			printf("%c is the counterfeit coin and it is %s.\n", ('A'+iCounterfeit), 
				((coin[iCounterfeit].type == HEAVY) ? "heavy" : "light") );
		}

	}
	return 0;
}
// definitions
// prepare
void prepare(COIN* coin)
{
	for(int i = 0; i < N; ++i)
	{
		coin[i].appear = false;
		coin[i].type   = UNDEFINED;
		coin[i].count  = 0;
	}
}
// update
void update(COIN* coin, char* pszLeft, char* pszRight, char* pszRelation)
{
	int iSize = strlen(pszLeft);
	char* psz[2] = { pszLeft, pszRight };
	if( strcmp(pszRelation, "even") == 0 ) // "even"
	{
		for(int i = 0; i < iSize; ++i)
		{
			for(int j = 0; j < 2; ++j)
			{
				int index = psz[j][i] - 'A';
				coin[index].appear = true;
				coin[index].type = DOLLAR;
			}
		}
	}
	else // "up" or "down"
	{
		int iTypeLeft, iTypeRight;
		if( strcmp(pszRelation, "up") == 0 )
		{
			iTypeLeft = HEAVY;
			iTypeRight = LIGHT;
		}
		else
		{
			iTypeLeft = LIGHT;
			iTypeRight = HEAVY;
		}
		for(int i = 0; i < iSize; ++i)
		{
			for(int j = 0; j < 2; ++j)
			{
				int index = psz[j][i] - 'A';
				coin[index].appear = true;
				coin[index].count++;
				if(coin[index].type != DOLLAR)
				{
					int iType = ((j>0) ? iTypeRight : iTypeLeft);
					if(coin[index].type == UNDEFINED)
						coin[index].type = iType;
					else if(coin[index].type != iType)
						coin[index].type = DOLLAR;
				}
			}
		}
	} // end else
}
// search
int search(COIN* coin)
{
	int iMaxCount = 0;
	int iCounterfeit = -1;
	for(int j = 0; j < N; ++j)
	{
		if(coin[j].appear && coin[j].type != DOLLAR && coin[j].count > iMaxCount)
		{
			iMaxCount = coin[j].count;
			iCounterfeit = j;
		}
	}
	return iCounterfeit;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值