2015_6
好题,有一副顺序随机的扑克牌,一张张翻开,问至少c,d,h,s张黑桃红心草花方片的期望要翻开的张数。其中两张鬼牌可以代替任意一种花色,当翻到鬼牌时,鬼牌要选择变成一种花色使得期望值最小,并且选完之后这张鬼牌就不能再变化了。两张鬼牌都一样且互不影响。
深搜记忆化dp,dp[a][b][c][d][e][f]存 从 a张黑桃 b张红心 c张草花 d张方片ef状态到符合题意的要求还需要翻的次数 的期望值, e 表示大鬼状态,f表示小鬼状态,e和f 为0表示未翻开,e和f==1,2,3,4,分别表示这张鬼变成某种颜色。
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 const int M=16; 5 double dp[M][M][M][M][8][8]; 6 int s[8]; 7 double dfs(int a,int b,int c,int d,int e,int f){ 8 double& tmp=dp[a][b][c][d][e][f]; 9 if(tmp!=-1) return tmp; 10 if(a+(e==1)+(f==1)>=s[0]&&b+(e==2)+(f==2)>=s[1]&&c+(e==3)+(f==3)>=s[2]&&d+(e==4)+(f==4)>=s[3]){ 11 tmp=0; 12 return tmp; 13 } 14 int tot=0; 15 tot+=13-a; 16 tot+=13-b; 17 tot+=13-c; 18 tot+=13-d; 19 tot+=(e==0); 20 tot+=(f==0); 21 double ans=1; 22 if(a<13){ 23 ans+=(13.0-a)/tot*dfs(a+1,b,c,d,e,f); 24 } 25 if(b<13){ 26 ans+=(13.0-b)/tot*dfs(a,b+1,c,d,e,f); 27 } 28 if(c<13){ 29 ans+=(13.0-c)/tot*dfs(a,b,c+1,d,e,f); 30 } 31 if(d<13){ 32 ans+=(13.0-d)/tot*dfs(a,b,c,d+1,e,f); 33 } 34 if(!e){ 35 double sma=dfs(a,b,c,d,1,f); 36 for(int i=2;i<5;i++){ 37 sma=min(sma,dfs(a,b,c,d,i,f)); 38 } 39 ans+=1.0/tot*sma; 40 } 41 if(!f){ 42 double sma=dfs(a,b,c,d,e,1); 43 for(int i=2;i<5;i++){ 44 sma=min(sma,dfs(a,b,c,d,e,i)); 45 } 46 ans+=1.0/tot*sma; 47 } 48 tmp=ans; 49 return tmp; 50 } 51 int main(){ 52 int t,cas=1; 53 while(~scanf("%d",&t)){ 54 while(t--){ 55 int sum=0; 56 for(int i=0;i<4;i++){ 57 scanf("%d",&s[i]); 58 if(s[i]>13) sum+=s[i]-13; 59 } 60 printf("Case %d: ",cas++); 61 if(sum>2){ 62 puts("-1.000"); 63 continue; 64 } 65 for(int i=0;i<14;i++){ 66 for(int j=0;j<14;j++){ 67 for(int x=0;x<14;x++){ 68 for(int y=0;y<14;y++){ 69 for(int a=0;a<5;a++){ 70 for(int b=0;b<5;b++){ 71 dp[i][j][x][y][a][b]=-1; 72 } 73 } 74 } 75 } 76 } 77 } 78 printf("%.3f\n",dfs(0,0,0,0,0,0)); 79 } 80 } 81 return 0; 82 }
题意是0123456789这10个数字,每一个可选可不选,最后问最少选几个可构成输入n个数字,如果个数相同则选择倒序的值小的选法。构成一个数字的方法有两种,一种是直接由所选数字构成,一种是构成两个数字之和是输入的数字。
2进制枚举+预处理 2的10次方表示每一位选或者不选
1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 #include<algorithm> 5 #define mt(a,b) memset(a,b,sizeof(a)) 6 using namespace std; 7 int a[16],digit[16],len[128]; 8 vector<int> sta[128]; 9 void add(int x){ 10 while(x){ 11 digit[x%10]++; 12 x/=10; 13 } 14 } 15 bool judge(){ 16 for(int i=0;i<10;i++){ 17 if(digit[i]>1) return false; 18 } 19 return true; 20 } 21 int get(){ 22 int res=0; 23 for(int i=9;i>=0;i--){ 24 res<<=1; 25 res|=digit[i]; 26 } 27 return res; 28 } 29 bool test(int x){ 30 mt(digit,0); 31 add(x); 32 return judge(); 33 } 34 bool test(int x,int y){ 35 mt(digit,0); 36 add(x); 37 add(y); 38 return judge(); 39 } 40 int getone(int x){ 41 int res=0; 42 while(x){ 43 if(x&1) res++; 44 x>>=1; 45 } 46 return res; 47 } 48 int main(){ 49 for(int i=1;i<=100;i++){ 50 sta[i].clear(); 51 } 52 for(int i=1;i<=100;i++){ 53 if(test(i)){ 54 sta[i].push_back(get()); 55 } 56 for(int j=1;j+j<=i;j++){ 57 if(test(j,i-j)){ 58 sta[i].push_back(get()); 59 } 60 } 61 } 62 for(int i=1;i<=100;i++){ 63 sort(sta[i].begin(),sta[i].end()); 64 len[i]=unique(sta[i].begin(),sta[i].end())-sta[i].begin(); 65 } 66 int n,cas=1,big=1<<10; 67 while(~scanf("%d",&n),n){ 68 for(int i=0;i<n;i++){ 69 scanf("%d",&a[i]); 70 } 71 int ans_cnt=11,ans_sta=0x3f3f3f3f; 72 for(int i=0;i<big;i++){ 73 int cnt=getone(i); 74 if(cnt>ans_cnt) continue; 75 if(cnt==ans_cnt&&i>ans_sta) continue; 76 bool ok=true; 77 for(int j=0;j<n;j++){ 78 bool flag=false; 79 for(int k=0;k<len[a[j]];k++){ 80 int his=sta[a[j]][k]; 81 if((i&his)==his){ 82 flag=true; 83 break; 84 } 85 } 86 if(!flag){ 87 ok=false; 88 break; 89 } 90 } 91 if(ok){ 92 if(ans_cnt>cnt){ 93 ans_cnt=cnt; 94 ans_sta=i; 95 continue; 96 } 97 ans_sta=min(ans_sta,i); 98 } 99 } 100 printf("Case %d: ",cas++); 101 for(int i=9;i>=0;i--){ 102 if(ans_sta&(1<<i)){ 103 printf("%d",i); 104 } 105 } 106 puts(""); 107 } 108 return 0; 109 }