能被15整除的最大整数
sources:http://cms.bit.edu.cn/moodle/mod/programming/view.php?a=5539
能被15整除的最大整数
成绩: 5 / 折扣: 0.8
给定一个只包含数字 [0..9] 的字符串,求使用字符串中的某些字符,构造一个能够被15整除的最大整数。注意,字符串中的每个字符只能使用一次。
输入:程序从标准输入读入数据,每行数据由一串数字组成,长度为1到1000。
输出:针对每一行输入,输出一个结果,每个结果占一行。如果无法构造出能够被15整除的整数,请输出impossible。
输入:程序从标准输入读入数据,每行数据由一串数字组成,长度为1到1000。
输出:针对每一行输入,输出一个结果,每个结果占一行。如果无法构造出能够被15整除的整数,请输出impossible。
思路,题目有意降低难度,为什么是15 而不是18 16 之类的,因为,15=3*5,这个就好办了。学过数论的都知道:
定理:如果15可以整除X(即X是15的倍数),那么5也可整除X,3也可以整除X。于是这道题目就变得简单。
5整除X,于是,X的末尾只能是0或者5。
3整除X,于是所有的数字之和必须是3的倍数。这就是为什么题目出一个15。
说一下思路:用cnt数组存放每个字符(0~9)出现的次数。stack存放,mod=1 、2 的数字是哪些,排个序存放。
然后,先用上所有的数字,不满足的话,一个个剔除。从小到大剔除,遍历所有剔除的方案,还是不满足,直接impossible。
ps:15可以整除0.,笔者因为介个,WA了N次。
欢迎转载,著名出处。
View Code
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<string.h>
4 char str[1005],ans0[1005],ans5[1005];//str为输入字符串,ans0、5为带输出的字符串
5 int cnt[10],stack[3][1005],sum;//sum,表示所有字符的数字之和,cnt[5]=6 表示 5出现过6次数,stack[2][4]表示符合mod=2 的第4个数,从小到大。
6 void into_str(char str[],int tag)
7 {//将cnt[]里面的数字按大小存放在字符串str里面,方便输出,tag标记一下末尾的数字
8 int e,j,k;
9 for(e=0,k=9;k>=0;k--)
10 for(j=0;j<cnt[k];j++)
11 str[e++]=k+'0';
12
13 if(tag==0)str[e++]='0';
14 else str[e++]='5';
15 str[e]='\0';
16 }
17 int solve(char str[],int tag)
18 {//剔除掉某些多余的数字,剔除的目的是为了改变cnt,然后将cnt中的数字塞进字符串str里面
19 int k;
20 switch(sum%3)//sum是所有数字之和
21 {
22 case 0://余0 表示不需要剔除数字
23 into_str(str,tag);return 1;
24 case 1://余1 表示需要剔除余数为1的数字,也可以剔除 两个2. ect
25 if(stack[1][0]!=0)//stack[1][0] 表示余数为1的数字的个数(个人习惯)
26 {//stack里面的数字已经按从小打到排序,可以剔除的话,当然是剔除第一个 stack[1][1];
27 cnt[stack[1][1]]--;into_str(str,tag);cnt[stack[1][1]]++;
28 return 1;
29 }
30 else if(stack[2][0]!=0)
31 if(tag == 0)
32 if(stack[2][0]==1)return 0;
33 else{
34 cnt[stack[2][1]]--;cnt[stack[2][2]]--;into_str(str,tag);
35 cnt[stack[2][1]]++;cnt[stack[2][2]]++;return 1;
36 }
37 else//tag=5
38 if(stack[2][0]<=2)return 0;
39 else
40 {//剔除两个 mod=2 的数字,由于5存在与stack中,所以会繁琐一点
41 for(k=1;k<=stack[2][0];k++)
42 if(stack[2][k]!=-1){cnt[stack[2][k]]--;break;}
43 for(k++;k<=stack[2][0];k++)
44 if(stack[2][k]!=-1){cnt[stack[2][k]]--;break;}
45 //转换成字符串
46 into_str(str,tag);
47 //恢复刚刚的改变
48 for(k=1;k<=stack[2][0];k++)
49 if(stack[2][k]!=-1){cnt[stack[2][k]]++;break;}
50 for(k++;k<=stack[2][0];k++)
51 if(stack[2][k]!=-1){cnt[stack[2][k]]++;break;}
52 return 1;
53 }
54 else return 0;//mod=1 or mod=2 都不能满足,说明impossible return 0
55 case 2://余数为2
56 if(stack[2][0]!=0)
57 if(tag==0)
58 {cnt[stack[2][1]]--;into_str(str,tag);cnt[stack[2][1]]++;return 1;}
59 else//tag==5 and 5 is in stack[2]
60 if(stack[2][0]>=2)
61 {
62 for(k=1;k<=stack[2][0];k++)
63 if(stack[2][k]!=-1){cnt[stack[2][k]]--;break;}
64 into_str(str,tag);
65 for(k=1;k<=stack[2][0];k++)
66 if(stack[2][k]!=-1){cnt[stack[2][k]]++;break;}
67 return 1;
68 }
69 //if it did not return here ,then goto mod 1
70 //mod 1
71 if(stack[1][0]<=1)return 0;// mod 1 or mod 2 都不满足
72 else
73 {//最前面的两个就是最小的,直接剔除
74 cnt[stack[1][1]]--;cnt[stack[1][2]]--;into_str(str,tag);
75 cnt[stack[1][1]]++;cnt[stack[1][2]]++;return 1;
76 }
77 default :break;
78 }
79 }
80
81 int main()
82 {
83 int i,j,n,tp0,tp5,index;//tp0、5 记录末尾为 0、5 的情况是不是可行。初始化为0
84 while(~scanf("%s",str))
85 {
86 memset(cnt,0,sizeof(cnt));
87 memset(stack,0,sizeof(stack));
88 memset(ans0,0,sizeof(ans0));
89 memset(ans5,0,sizeof(ans5));
90 tp0=tp5=0;
91 n=strlen(str);
92 for(sum=i=0;i<n;i++)
93 {
94 index=str[i]-'0';
95 cnt[index]++;
96 sum+=index;
97 }
98 for(i=0;i<10;i++)
99 for(j=0;j<cnt[i];j++)
100 if(i%3) stack[i%3][++stack[i%3][0]]=i;//只需记录余数为1 or 2,mod=0 不需要记录,mod=0 踢不踢除都没关系
101 else continue;
102
103 if(cnt[0]==0 && cnt[5]==0){printf("impossible\n");continue;}
104 if(cnt[0]!=0)
105 {
106 cnt[0]--;
107 tp0=solve(ans0,0);
108 cnt[0]++;
109 }
110 if(cnt[5]!=0)
111 {
112 cnt[5]--;//5作为末尾的元素,需要在stack中标记一下,避免重复使用
113 for(j=1;j<=stack[2][0];j++)if(stack[2][j]==5){stack[2][j]=-1;break;}
114
115 tp5=solve(ans5,5);
116 cnt[5]++;
117 //恢复
118 for(j=1;j<=stack[2][0];j++)if(stack[2][j]==-1){stack[2][j]=5;break;}
119 }
120 if(tp0==0 && tp5==0){printf("impossible\n");continue;}
121 if(tp0==0 || strcmp(ans0,ans5)<0)
122 if(ans5[0]=='0')//{printf("impossible\n");continue;} 笔者曾经以为15不整除0,所以输出impossible,结果wa了N次
123 {printf("0\n");continue;}
124 else {printf("%s\n",ans5);continue;}
125 if(tp5==0 || strcmp(ans0,ans5)>=0)
126 if(ans0[0]=='0')//{printf("impossible\n");continue;}
127 {printf("0\n");continue;}
128 else {printf("%s\n",ans0);continue;}
129 }
130 return 0;
131 }