vjudge 4965.Sum the Square | 使用map

4965 - Sum the Square

Time limit: 3.000 seconds

Take any positive number, find the sum of the squares of its digits, repeat! You'll end up with an infinite sequence with an interesting property that we would like to investigate further. Starting with the number 5, the sequence is:

(5, 25, 29, 85, 89, 145, 42, 20, 4, 16, 37, 58,...)

The interesting part is in what comes after 58: 52 +82 = 89 which is a number that's already been seen in the sequence. In other words, after 58, the sequence will fall into the repeating cycle: 89, 145, 42, 20, 4, 16, 37, 58.

What's amazing is that this cycle will appear for many other numbers: 3, 18, 36, and 64 just to name a few. (see figure on the following page.)

For some numbers, the sequence will fall into another repeating cycle by reaching 1. (see second figure on the following page) For example, starting with 19, you'll end up with the sequence:

(19, 82, 68, 100, 1,...)

And that's about it. Any number you choose will end up falling into a repeating cycle: Either the 89, 145,... cycle or the 1, ... cycle.

Given two numbers, your objective is to generate as few numbers in their sequences for the two sequences to intersect at one common number. For example, given 61 and 29, we can achieve what's required by generating the sequences: (61, 37, 58, 89) and (29, 85, 89). Similarly, for 19 and 100, the sequences would be (19, 82, 68, 100) and (100).

Input 

Your program will be tested on one or more test cases. Each test case is specified on a single line having two integers (0 < AB < 109).

The last case is followed by a dummy line made of two zeros.

Output 

For each test case, print the following line:


A $ \sqcup$ B $ \sqcup$ S


Where AB are as in the input and S is the (minimum) sum of the lengths of the two sequences. If the sequences starting at A and B do not intersect, then S = 0.

\epsfbox{p4965a.eps}

Few numbers falling into the 89, 145, 42, 20, 4, 16, 37, 58 cycle.

\epsfbox{p4965b.eps}

Few numbers falling into the 1 cycle.

Sample Input 

89 89 
19 100 
61 19 
0 0

Sample Output 

89 89 2 
19 100 5 
61 19 0


思路:对于以A开头的序列,先用map<int,int>类型变量c保存对应数字在序列的所在位置,遇到已经出现的数字就停止查找。 如:A=16,其后面的数字为:37、58、59, 则c[16]=1,c[37]=2,c[58]=3,c[59]=4,...

对于以B开头的序列,只需要用map<int,int>类型变量d判断对应数字是否已经出现在之前的序列中,如B=16,则d[16]=1,d[37]=1,...遇到已经出现的数字时停止查找。在这个过程中,判断该序列当前的数字是否已经在c中出现过(注意不是遇到一个已经在c中出现的数字就停止查找,这种情况下的s可能不是最小的),用一个变量lenmin记录s最小的值。

代码:
#include<iostream>
#include<map> 
#include<cstdio>
using namespace std;

int f(int n)//计算n的下一位 
{
	int sum=0;
	int t=0;
	while(n)
	{
		t=n%10;
		sum+=t*t;
		n/=10;
	}
	return sum;
}
int main()
{
	int a,b,t;
	while(cin>>a>>b)
	{
		if(!a&&!b) break;
		if(a==b)//两个数字相同 则s为2 
		{
			cout<<a<<" "<<b<<" "<<2<<endl; 
			continue;
		}
		
		map<int,int> c,d;
		int cnt=1,p=a;
		while(1)//储存以a开头的序列 ,遇到已经出现的数字则停止查找 
		{
			if(c.find(p)==c.end()) c[p]=cnt;//若序列还没有进入循环,标记数字p在序列中的位置
			else break;
			t=f(p);
			cnt++;
			p=t;
		}
		
		int len=0,lenmin=1147483646;
		p=b;
		while(1)
		{
			//cout<<p<<" ";
			if(d.find(p)!=d.end())//若p,当前得出的序列的最后一个数,已经出现过了,则跳出循环 
			{
				if(lenmin==1147483646) lenmin =0;
				break;
			}
			else//否则 标记 
			{
				d[p]=1;	
			}
			
			if(c.find(p)==c.end()) //若没有出现在 以a开头的那个序列 
			{
				len++;
			}
			else 
			{
				if(len+c[p]+1<lenmin)//比较是否最小 
				{
					lenmin=len+c[p]+1;
				}
				len++;
			}
			t=f(p);
			p=t;
		}
		cout<<a<<" "<<b<<" "<<lenmin<<endl;
	}
} 

仔细再看下代码,发现有些冗余,于是重新修改,如下:
#include<iostream>
#include<map> 
#include<cstdio>
using namespace std;

int f(int n)//计算n的下一位 
{
	int sum=0;
	int t=0;
	while(n)
	{
		t=n%10;
		sum+=t*t;
		n/=10;
	}
	return sum;
}
int main()
{
	int a,b;
	while(cin>>a>>b)
	{
		if(!a&&!b) break;
		if(a==b)//两个数字相同 则s为2 
		{
			cout<<a<<" "<<b<<" "<<2<<endl; 
			continue;
		}
		
		map<int,int> c,d;
		int cnt=1,p=a;
		while(1)//储存以a开头的序列 ,遇到已经出现的数字则停止查找 
		{
			if(c.find(p)==c.end()) c[p]=cnt;
			else break;
			p=f(p);
			cnt++;
		}
		
		int lenmin=2147483646;
		cnt=0,p=b;
		while(1)
		{
			if(d.find(p)!=d.end())//若p,当前得出的序列的最后一个数,已经出现过了,则跳出循环 
			{
				if(lenmin==2147483646) lenmin =0;
				break;
			}
			else//否则 标记 
			{
				d[p]=cnt;	
			}
			cnt++;
			if(c.find(p)!=c.end()) //若p出现在 以a开头的那个序列 
			{
				if(cnt+c[p]<lenmin)//比较是否最小 
				{
					lenmin=cnt+c[p];
				}
			}
			p=f(p);
		}
		cout<<a<<" "<<b<<" "<<lenmin<<endl;
	}
} 




                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值