题目:
Notice that the number 123456789 is a 9-digit number consisting exactly the numbers from 1 to 9, with no duplication. Double it we will obtain 246913578, which happens to be another 9-digit number consisting exactly the numbers from 1 to 9, only in a different permutation. Check to see the result if we double it again!
Now you are suppose to check if there are more numbers with this property. That is, double a given number with k digits, you are to tell if the resulting number consists of only a permutation of the digits in the original number.
Input Specification:
Each input contains one test case. Each case contains one positive integer with no more than 20 digits.
Output Specification:
For each test case, first print in a line "Yes" if doubling the input number gives a number that consists of only a permutation of the digits in the original number, or "No" if not. Then in the next line, print the doubled number.
Sample Input:
1234567899
Sample Output:
Yes
2469135798
这里的位数较多,unsigned long long不够用,只能用数组了
这里使用scanf+字符数组
通过记录每一位的数字计数(解法一),也可以通过int数组下标0~9的对应的数表示这十个数字的出现次数(解法二)
解法一:
/*
输入一个数,将其乘二,如果结果是输入数字的各位数字的重组,则输出"Yes"否则输出"No"之后在下一行输出乘二的结果
输入的是不超过20位的正整数
*/
#include <stdio.h>
int main()
{
int i, flag[20]={0},flag2,j,t,jin,s;
/*flag[20]用来标记该位是否有数字(0),是否被找到(1) t用来标记输入的最小一位 flag2表示该位是否找到*/
char in[20],o[21]; //20位太大了只能用字符数组
jin=0; //jin是进位标记位
s=1; //s即start,打印数的时候从o[0]位还是从o[1]位开始
i=0; //工具人
scanf("%c",&in[i]);
while(in[i]<='9'&&in[i]>='0')
{
i++;
scanf("%c",&in[i]);
}
in[i]='\0';
t=--i; //此时i=t=最后一位所在的位置
// printf("t=%d",t); //看下t的情况 应该是正确的
// for(i=0;i<=t;)
// {
// printf("in[i]=%c i=%d\n",in[i],i); //打印出每一位
// i++;
// }
while(i>=0) //开始一位一位乘以2 并进位
{
int temp;
temp=in[i]-'0';
// printf("temp=%d ",temp);
if(temp<=4)
{
o[i+1]=2*temp+'0'+jin;
jin=0; //进位标记位
s=1; //好像是判断比赋值占资源
}
else //第一位大于4就是说直接进位,那就直接输出"No"
{
o[i+1]=2*temp%10+'0'+jin;
jin=1;
s=0;
}
i--;
}
if(jin) //如果最后需要进一位
{
o[0]=1; //最高位置1
}
for(i=0;i<=t;i++) //t这时候在in[]最后一个数字上
{
flag2=0; //找每一位的时候都要置0,找到再置1
if(jin) //最高位需要进位
{
o[0]='1';
// printf("a");
break;
}
for(j=1;j<=t+1;j++)
{
if(o[j]==in[i]&&flag[i]==0)
{
flag2=1; //找到就置1
flag[i]=1; //找过的一个in[]就标记
break;
}
// printf("o[%d]=%c in[%d]=%c\n",j,o[j],i,in[i]);
}
if(flag2==0) //没找到
{
break;
}
}
if(flag2==0) //异常结束 即在允许找寻的位没找到或者最高位大于4
{
printf("No\n");
}
else if(flag2==1)
{
printf("Yes\n");
}
for(i=s;i<=t+1;i++) //从s位开始(如果最高位进位就是0否则是1)
{
printf("%c",o[i]); //正常打印两倍
}
return 0;
}
解法二:
#include <stdio.h>
int dbanumber(int a[],char b[],int k);
/*
函数功能:
将一个装在char b[]里面的数乘二,如果最高位进位就返回-1,
没用完int a[]里面的数字就返回1;用完且不进位返回0
*/
int main(int argc,char argv[])
{
int a[10]={0}; //装各个数字个数的数组
char b[20]; //装输入数的字符组
int i=0,num=0,flag=9; //flag用来装函数的返回值
do{
scanf("%c",&b[i]);
if(b[i]<='9'&&b[i]>='0')
{
a[b[i]-'0']++; //输入一个数字i,该数字对应的a[i]加一
}
i++;
}while(b[i-1]<='9'&&b[i-1]>='0');
num=i-1;
flag=dbanumber(&a[0],&b[0],i);
if(flag==0) //根据返回值打印结果
{
printf("Yes\n");
}
else if(flag==1)
{
printf("No\n");
}
else if(flag==-1) //这里的1是因为最高位发生进位
{
printf("No\n1");
}
for(i=0;i<num;i++) //把修改后的字符数组打印出来
{
printf("%c",b[i]);
}
return 0;
}
int dbanumber(int a[],char b[],int k) //将一个装在char b[]里面的数乘二,如果最高位进位就返回-1,没用完int a[]里面的数字就返回1;用完且不进位返回0
{
int i,t,co,flag;
flag=0;
co=0;
for(i=k-2;i>=0;i--)
{
t=b[i]-'0';
t=t*2+co; //t为乘二且进位后但未将十位进上去的该位的数
if(t>9)
{
t=t%10; //co用来记录进到下一位的进位标记位 t用来记录此一位
co=1;
}
else
{
co=0;
}
a[t]--; //数字t的数目对应的a[t]
if(a[t]<0&&flag==0) //此时发现多了某位上的数字
{
flag=1; //发现后就不需要再找了
}
b[i]=t+'0'; //
}
if(co) //发现发生进位
{
flag=-1;
}
return flag;
}