1.猜数字游戏的提示(Master-Mind Hints,Uva 340)
题目:给定答案序列和用户猜的序列,统计有多少数字位置正确(A),有多少数字在两个序列都出现了但位置不对(B)。
输入包含多组数据。每组输入第一行为序列长度n,第二行是答案序列,接下来是猜测序列。猜测序列全0时,该组数据结束。n=0时输入结束。
样例输入:
4
1355
1123
4335
6551
6135
1355
0000
10
1222456669
1234567891
1122334455
1213151619
1225556667
0000000000
0
样例输出:
Game 1:
(1,1)
(2,0)
(1,2)
(1,2)
(4,0)
Game 2:
(2,4)
(3,2)
(5,0)
(7,0)
分析:这题的关键是要理解A和B各代表什么,弄清了这一点,解法还是容易想到的。直接统计可以得到A,而求B,对于每一个数字(1~9),统计在两个序列中分别出现的次数c1和c2,则min(c1,c2)就是该数字对B的贡献。最后求B还要减去A的部分。
代码如下:
#include<stdio.h>
#define maxn 1010
int main()
{
int n,a[maxn],b[maxn];
int kase=0;
while(scanf("%d",&n)==1&&n) ①
{
printf("Game %d:\n",++kase);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
for(;;)
{
int A=0,B=0,s=0;
for(int i=0;i<n;i++)
{
scanf("%d",&b[i]);
s+=b[i];
if(a[i]==b[i]) A++;
}
if(s==0) break;
for(int j=1;j<=9;j++)
{
int c1=0,c2=0;
for(int i=0;i<n;i++)
{
if(a[i]==j) c1++;
if(b[i]==j) c2++;
}
B+=c1<c2?c1:c2;
}
printf(" (%d,%d)\n",A,B-A);
}
}
return 0;
}
PS: ①当
题目要求“n=x时结束输入”时,采用的方式
2.生成元(Digit Generator,ACM/ICPC Seoul 2005,UVa1583)
如果x加上x的各个数字之和得到y,就说x是y的生成元。给出n(1<=n<=100000),求最小生成元。无解就输出0。
样例输入:
3
216
121
2005
样例输出:
198
0
1979
分析:本题乍一看觉得有点难以入手,因为要想由n直接推出解,难度有点大。但是,从解却可以很容易地推出n。而且可以发现解总是小于n,那么不难想到可以通过“暴力”枚举1~n,“逆向”生成各个数,最后看有没有哪个数与n相等。但是若是每输入一个n,都枚举一遍,效率肯定是不高的,所以试想可不可以一次性枚举所有的,制成一张表,以后只需查表就行了呢?(正难则反)很容易想到常量数组,以n作为下标,数组内容就是根据n推出来的答案,而n的范围题目也有。不过注意一点,就是题目要求的“最小”生成元。
代码如下:
#include<stdio.h>
#include<string.h>
#define maxn 100001
int main()
{
int ans[maxn];
int T,n;
memset(ans,0,sizeof(ans));
for(int i=1;i<maxn;i++)
{
int n=i,m=i;
while(n>0)
{
m+=n%10;
n/=10;
} //①
if(ans[m]==0||i<ans[m]) ans[m]=i; //②
}
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
printf("%d\n",ans[n]);
}
return 0;
}
PS:①这段代码的核心就是如何
求取数字各位上的数,常规方法就是对n位数,就用n个变量来分别存储各位上的数,可是本题数是几位数不是明确的,显然这样的做法不好。所以采用了
“过河拆桥”的方式,
即每次求取末尾数,求完就“割”掉,直到全部“割”完为止
②这是为了满足题目生成元“最小”的要求