初学acmer--读《算法竞赛入门经典》笔记(八)p50-52

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个变量来分别存储各位上的数,可是本题数是几位数不是明确的,显然这样的做法不好。所以采用了 “过河拆桥”的方式, 即每次求取末尾数,求完就“割”掉,直到全部“割”完为止

    ②这是为了满足题目生成元“最小”的要求


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值