题目的意思是有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;
}