题意:每组数据给出n个数,每个数在1-100,问组成这些数的蜡烛的权值的最小值。权值=把选的蜡烛从大到小排列组成的数
组成方式:比如有1 3两个蜡烛 可以组成13(1和3)或4(1+3) 只有一个加号可以用
解:位运算记录状态,can[i][j]表示在i的二进制所记录的状态下能不能组成j
can直接预处理出来,分类讨论 用一个数表示 还是用两个数表示 check的时候都在100以内 直接枚举
1 #include<cstdio> 2 #include<cmath> 3 #include<algorithm> 4 #include<cstring> 5 6 using namespace std; 7 8 int n; 9 bool can[1024][101]; 10 int a[11]; 11 int cas=0; 12 13 bool check1(int x,int y,int z){ 14 int cnt[11]; 15 memset(cnt,0,sizeof(cnt)); 16 int tmp=y; 17 while (tmp!=0){ 18 int now=tmp%10; 19 tmp=tmp/10; 20 if (((x&(1<<now))==0)||(cnt[now]>0)) return false; 21 cnt[now]++; 22 } 23 tmp=z; 24 while (tmp!=0){ 25 int now=tmp%10; 26 tmp=tmp/10; 27 if (((x&(1<<now))==0)||(cnt[now]>0)) return false; 28 cnt[now]++; 29 } 30 return true; 31 } 32 33 bool check(int x,int y){ 34 if ((y<10)&&(x&(1<<y))) return true; 35 for (int i=1;i<=y/2;i++){ 36 if (i!=(y-i)){ 37 if (check1(x,i,y-i)) return true; 38 } 39 } 40 if (y==100) return false; 41 int tmpy1=y/10; 42 int tmpy2=y%10; 43 if (tmpy1==tmpy2) return false; 44 if ((x&(1<<tmpy1))==0) return false; 45 if ((x&(1<<tmpy2))==0) return false; 46 return true; 47 } 48 49 int main(){ 50 memset(can,0,sizeof(can)); 51 for (int i=1;i<1024;i++){ 52 for (int j=1;j<=100;j++) can[i][j]=check(i,j); 53 } 54 while (1){ 55 scanf("%d",&n); 56 if (n==0) return 0; 57 cas++; 58 bool flag; 59 int ans=0; 60 for (int i=1;i<=n;i++) scanf("%d",&a[i]); 61 for (int i=1;i<1024;i++){ 62 flag=true; 63 for (int j=1;j<=n;j++) if (!can[i][a[j]]) flag=false; 64 if (flag){ 65 int tmp=0; 66 for (int j=9;j>=0;j--) if (i&(1<<j)) tmp=tmp*10+j; 67 if ((ans==0)||(ans>tmp)) ans=tmp; 68 } 69 } 70 printf("Case %d: %d ",cas,ans); 71 } 72 return 0; 73 } 74 /* 75 2 10 11 76 1 30 77 0 78 */ 79