假币问题

问题描述

利有 12 枚银币。其中有 11 枚真币和 1 枚假币。假币看起来和真币没有区别,但是重量不同。但赛利不知道假币比真币轻还是重。于是他向朋友借了一架天平。朋友希望赛利称三次
就能找出假币并且确定假币是轻是重。例如:如果赛利用天平称两枚硬币,发现天平平衡,说明两枚都是真的。如果赛利用一枚真币与另一枚银币比较,发现它比真币轻或重,说明它是假币。经过精心安排每次的称量,赛利保证在称三次后确定假币。

Input:

输入有三行,每行表示一次称量的结果。赛利事先将银币标号为 A-L。每次称量的结果用三个以空格隔开的字符串表示: 天平左边放置的硬币 天平右边放置的硬币 平衡状态。 其中平衡状态用,up, down, 或 even表示, 分别为右端高、右端低和平衡。天平左右的硬币数总是相等的。

Output:

输出哪一个标号的银币是假币,并说明它比真币轻还是重(heavy or light)。
Sample Input
1
ABCD EFGH even
ABCI EFJK up
ABIJ EFGH even
Sample Output
K is the counterfeit coin and it is light

思路

核心(枚举)

首先,每一个标号的银币都可能是假币,所以需要对每个银币都进行分析,其次题目没说假币是更重还是更轻,所以又要再分俩种情况。

具体实现则是,读入三次称重结果,对每一枚银币,分更重和更轻俩种情况讨论,看哪种符合读入的结果。

比如这次的输入,ABCD EFGH even,说明假币不可能在这8枚银币里,但程序仍会对A-H进行分析,再分析I,先假设I更轻,第二个就不满足了,因为up表示右边高,I排除,再分析J,同样
先假设J更轻,第三个就不满足了,最后剩一个K,先假设更轻,刚好满足第二个条件。

所以程序需要实现的就是这三个过程,遍历A-L,假币更重比较一次,假币更轻比较一次。

用到了strchr(const char str[], int c),如果在字符串 str 中找到字符 c,则函数返回指向该字符的指针,如果未找到该字符则返回 NULL。假币在天平上肯定出现不平衡,所以找出事先假设好的假币在哪边,再判断。

代码

#define _NO_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
char left[3][7];//天平左边的银币
char right[3][7];//天平右边的银币
char result[3][7];//称量结果
bool isCounterfeitCoin(char iCoin, bool isLight);
int main()
{
int t;
scanf("%d", &t);//t组数据,一组三次
while (t--) {
for (int i = 0; i < 3; i++)
scanf("%s %s %s", &left[i], &right[i], &result[i]);
//枚举每个银币

for(char iCoin = 'A'; iCoin <= 'L'; iCoin++)
if (isCounterfeitCoin(iCoin, true)) {
printf("%c is the counterfeit coin and it is light.\n", iCoin);
break;
}
else if (isCounterfeitCoin(iCoin, false)) {
printf("%c is the counterfeit coin and it is heavy.\n", iCoin);
break;
}
}
return 0;
}
bool isCounterfeitCoin(char iCoin, bool isLight) /*isLight为真则表示假币为轻,否则假币为重*/
{
for (int i = 0; i < 3; ++i) {
//指向天平俩边的字符串
char* pleft;
char* pright;
if (isLight) {
pleft = left[i];
pright = right[i];
}
else { /*如果假设假币是重的isLight为假的,则把称量结果左右对换*/
pleft = right[i];
pright = left[i];
}
switch (result[i][0]) {/*天平右边的情况*/
case 'u': // up
if (strchr(pright, iCoin) == NULL)
return false;
break;
case 'e': //even
if (strchr(pleft, iCoin) || strchr(pright, iCoin))
return false;
break;
case 'd':
if (strchr(pleft, iCoin) == NULL)
return false;
break;
}
}
return true;
}

image.png

跳绳为题 (参考自:)

题目描述

朋友玩跳绳比赛,要计算在一分钟内跳了多少下.假设每秒钟跳一下,如果中途失败了,则要
花三秒钟后才能开始重跳.一般小朋友跳绳一分钟要跳坏好几次.现在给出小朋友每次跳坏时
已经跳的总数,求小朋友在一分钟内跳了多少下.(请注意分析示例数据.)

Input:

第一行为 n 个小朋友
其余各行,每行第一个整数是跳坏的次数 m,其余 m 个整数是跳坏时累计跳了多少下.

Output:

输出相应小朋友头一分钟内跳了多少下.

Sample Input

603
12 23 451 17
4 10 20 30 40
5 10 20 30 40 58
6 10 20 30 40 47 60

Sample Output

60
51
57
48
48
47
Hint

提示,在跳绳比赛时,你可能已经超时了,但自己还在计数,但裁判已经停止计时并得到成绩.
这里相当与自己计数.因此,并非跳坏的时候都是在前一分钟以内.请注意分析示例数据

思路

代码

#include<stdio.h>
int main()
{
int n, m, x, i, ok, time, s;
scanf("%d", &n);
while (n--)
{
time = ok = s = 0;
scanf("%d", &m);
for (i = 0; i < m; ++i)
{
scanf("%d", &x);
time = x + 3 * i;//每次停下来后已经用的时间
if (ok == 0)//未超过一分钟...
{
if (time >= 57)
{
ok = 1;
time = (time > 60) ? 60 : time;//最多跳60次
s = time - 3 * i;
//剩余的时间不够下一次重新跳了
//跳的次数等于用的时间减去停下来消耗的时间
}
else if (time < 57 && i == m - 1)
//最后一次停下来,但是不够60s
{
s = 60 - 3 * (i + 1);
//这一次后面肯定还要有三秒停下来的时间
}
}
}
printf("%d\n", (m == 0) ? 60 : s);//特判未停下来的情况
}
return 0;
}

image.png