poj 1013 Counterfeit Dollar

题目的意思是有12个币,其中一个是假的,假币可能比真币重,也可能轻。有一个天平,可以称三次,三次称那些硬币和称的结果已经给出来了,问你根据这个结果,那个币是假的,他是重还是轻。

首先,如果天平是even,毋庸置疑,每个币都是真的。剩下的难点就在于判断其他硬币是真是假。

先看一组数据
先看第一行
ABCD EFGH up
我们可以怀疑ABCD都可能是假币,而且是重的那个;或者EFGH都可能是假币,而且是轻的那个。我们先把这些怀疑记录下来。
再看第二行
AIJK EFGH down
这时候联系第一行,如果A是假币,那么A是重的那个,A造成了第一次天平up,但是对于第二行数据,因为只有一个假币,那么造成第二次天平down的也是A,重币造成己侧down???(己侧表示自已所在的一侧),这时候就产生了矛盾。一个硬币不可能造成己侧up又造成己侧down(只有一个假币),所以这时候A一定是真币。同理EFGH也一定是真币。
所以我们可以记录每个硬币造成己侧的偏移,如果up和down同时出现,此币一定为真。

同时对于不能确定是否为真的币,我们选最可能是假币的。

#include <iostream>
#include <cstdio>
#include <iomanip>
#include <string>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <set>
#include <vector>
#include <map>
#include <algorithm>
#include <cmath>

#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f
#define ll long long
#define ull unsigned long long
#define uint unsigned int
#define l(x) x<<1
#define r(x) x<<1|1
#define ms(a,b) memset(a,b,sizeof(a))

using namespace std;

int t;
string str1,str2,str3;
int demo[220];
int jilu[220];

int main() {
	cin >> t;
	while (t--) {
		ms(demo, 0);
		ms(jilu, 0);
		for (int j = 0; j < 3; j++) {
			cin >> str1 >> str2 >> str3;
			if (str3 == "even") {
				for (int i = 0; i < str1.size(); i++) jilu[str1[i] - 'A'] = 1;
				for (int i = 0; i < str2.size(); i++) jilu[str2[i] - 'A'] = 1;
			}
			else if (str3 == "up") {
				for (int i = 0; i < str1.size(); i++) {
					if (demo[str1[i] - 'A'] < 0) {
						jilu[str1[i] - 'A'] = 1;
					}
					else {
						demo[str1[i] - 'A']++;
					}
				}
				for (int i = 0; i < str2.size(); i++) {
					if (demo[str2[i] - 'A'] > 0) {
						jilu[str2[i] - 'A'] = 1;
					}
					else {
						demo[str2[i] - 'A']--;
					}
				}
			}
			else {
				for (int i = 0; i < str1.size(); i++) {
					if (demo[str1[i] - 'A'] > 0) {
						jilu[str1[i] - 'A'] = 1;
					}
					else {
						demo[str1[i] - 'A']--;
					}
				}
				for (int i = 0; i < str2.size(); i++) {
					if (demo[str2[i] - 'A'] < 0) {
						jilu[str2[i] - 'A'] = 1;
					}
					else {
						demo[str2[i] - 'A']++;
					}
				}
			}
		}
		
		int max = 0;
		char ans;
		for (int i = 0; i < 12; i++)
		{
			if (abs(demo[i]) > max && jilu[i] == 0)
			{
				max = abs(demo[i]);
				ans = 'A' + i;
			}
		}
		if (demo[ans - 'A'] > 0)
			cout << ans << " is the counterfeit coin and it is heavy." << endl;
		if (demo[ans - 'A'] < 0)
			cout << ans << " is the counterfeit coin and it is light." << endl;
	}

	return 0;
}

但是对于必定为真的那种,其实直接demo[str2[i] - ‘A’]–,他的demo值就一定小于其他的,所以可以做一下优化

#include <iostream>
#include <cstdio>
#include <iomanip>
#include <string>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <set>
#include <vector>
#include <map>
#include <algorithm>
#include <cmath>

#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f
#define ll long long
#define ull unsigned long long
#define uint unsigned int
#define l(x) x<<1
#define r(x) x<<1|1
#define ms(a,b) memset(a,b,sizeof(a))

using namespace std;

int t;
string str1,str2,str3;
int demo[220];
int jilu[220];

int main() {
	cin >> t;
	while (t--) {
		ms(demo, 0);
		ms(jilu, 0);
		for (int j = 0; j < 3; j++) {
			cin >> str1 >> str2 >> str3;
			if (str3 == "even") {
				for (int i = 0; i < str1.size(); i++) jilu[str1[i] - 'A'] = 1;
				for (int i = 0; i < str2.size(); i++) jilu[str2[i] - 'A'] = 1;
			}
			else if (str3 == "up") {
				for (int i = 0; i < str1.size(); i++) demo[str1[i] - 'A']++;
				for (int i = 0; i < str2.size(); i++) demo[str2[i] - 'A']--;
			}
			else {
				for (int i = 0; i < str1.size(); i++) demo[str1[i] - 'A']--;
				for (int i = 0; i < str2.size(); i++) demo[str2[i] - 'A']++;
			}
		}
		
		int max = 0;
		char ans;
		for (int i = 0; i < 12; i++)
		{
			if (abs(demo[i]) > max && jilu[i] == 0)
			{
				max = abs(demo[i]);
				ans = 'A' + i;
			}
		}
		if (demo[ans - 'A'] > 0)
			cout << ans << " is the counterfeit coin and it is heavy." << endl;
		if (demo[ans - 'A'] < 0)
			cout << ans << " is the counterfeit coin and it is light." << endl;
	}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值