初学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
    评论
华为od 序列中的数字和等于给定的数字,首先需要明确华为od序列是什么。华为od序列是华为公司提出的一种数字序列,其特点是每个数字都是前两个数字的和。例如,序列的第一个数字为1,第二个数字也为1,第三个数字为前两个数字之和,即1+1=2,第四个数字为前两个数字之和,即1+2=3,以此类推。 如果我们要找到华为od序列中数字和等于给定的数字,可以按照以下步骤进行: 1. 设定两个变量,分别表示华为od序列中的第一个数字和第二个数字,初始值为1。 2. 判断给定的数字是否等于序列中第一个数字或第二个数字,如果是,则直接输出该数字即可。 3. 若给定的数字大于序列中第一个数字或第二个数字,则进行循环遍历。 4. 在循环中,每次都计算当前数字为前两个数字之和,并将其与给定的数字进行比较。 5. 如果当前数字等于给定的数字,则输出该数字,并结束循环。 6. 如果当前数字大于给定的数字,则说明给定的数字在华为od序列中不存在,输出不存在相关数字的提示。 7. 如果当前数字小于给定的数字,则将第一个数字更新为第二个数字,将第二个数字更新为当前数字,并继续循环。 通过以上步骤,我们可以找到华为od序列中数字和等于给定的数字。这样的方法能够在较快的时间内找到结果,并且保证结果的正确性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值