Tyvj 2002 扑克牌
P2002 扑克牌
时间: 1000ms / 空间: 131072KiB / Java类名: Main
背景
Admin生日那天,Rainbow来找Admin玩扑克牌……
玩着玩着Rainbow觉得太没意思了,于是决定给Admin一个考验~~~
玩着玩着Rainbow觉得太没意思了,于是决定给Admin一个考验~~~
描述
Rainbow把一副扑克牌(54张)随机洗开,倒扣着放成一摞。然后Admin从上往下依次翻开每张牌,每翻开一张黑桃、红桃、梅花或者方块,就把它放到对应花色的堆里去。
Rainbow想问问Admin,得到A张黑桃、B张红桃、C张梅花、D张方块需要翻开的牌的张数的期望值E是多少?
特殊地,如果翻开的牌是大王或者小王,Admin将会把它作为某种花色的牌放入对应堆中,使得放入之后E的值尽可能小。
由于Admin和Rainbow还在玩扑克,所以这个程序就交给你来写了~
Rainbow想问问Admin,得到A张黑桃、B张红桃、C张梅花、D张方块需要翻开的牌的张数的期望值E是多少?
特殊地,如果翻开的牌是大王或者小王,Admin将会把它作为某种花色的牌放入对应堆中,使得放入之后E的值尽可能小。
由于Admin和Rainbow还在玩扑克,所以这个程序就交给你来写了~
输入格式
输入仅由一行,包含四个用空格隔开的整数,A,B,C,D。
输出格式
输出需要翻开的牌数的期望值E,四舍五入保留3位小数。
如果不可能达到输入的状态,输出-1.000。
如果不可能达到输入的状态,输出-1.000。
测试样例1
输入
样例输入1
1 2 3 4
样例输入2
15 15 15 15
输出
样例输出1
16.393
样例输出2
-1.000
备注
对于100%的数据,0<=A,B,C,D<=15
lydrainbowcat - "Admin生日"杯NOIP模拟赛 第三题
Blog: www.lydrainbowcat.tk Email: lyd@tyvj.cn
lydrainbowcat - "Admin生日"杯NOIP模拟赛 第三题
Blog: www.lydrainbowcat.tk Email: lyd@tyvj.cn
Solution
我又把题目看错了ToT
因为翻到大小王的时候,比较特殊,需要知道之后的答案,所以可以用记忆化搜索
讲道理,dp过程中不存在无解的情况,但是由于翻到大小王的时候要找一种期望最小的情况,所以会出现无解的情况,这是不能取的,所以要返回inf
#include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> #include<queue> using namespace std; int A,B,C,D,inf=100000000; double f[15][15][15][15][5][5]; int read() { int ans=0,f=1;char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)) {ans=ans*10+ch-'0';ch=getchar();} return ans*f; } bool ok(int a,int b,int c,int d,int w1,int w2) { if(w1==1) a++; if(w1==2) b++; if(w1==3) c++; if(w1==4) d++; if(w2==1) a++; if(w2==2) b++; if(w2==3) c++; if(w2==4) d++; if(a<A||b<B||c<C||d<D) return 0; else return 1; } double dp(int a,int b,int c,int d,int w1,int w2) { double ans=0,n,mi; if(f[a][b][c][d][w1][w2]!=-1) return f[a][b][c][d][w1][w2]; n=a+b+c+d; if(w1) n++; if(w2) n++; if(ok(a,b,c,d,w1,w2)) return 1.0*n; if(n>=54) return inf; ////////////////////// if(a+1<=13) ans+=(double)(13-a)*1.0/(54-n)*dp(a+1,b,c,d,w1,w2); //强转 if(b+1<=13) ans+=(double)(13-b)*1.0/(54-n)*dp(a,b+1,c,d,w1,w2); if(c+1<=13) ans+=(double)(13-c)*1.0/(54-n)*dp(a,b,c+1,d,w1,w2); if(d+1<=13) ans+=(double)(13-d)*1.0/(54-n)*dp(a,b,c,d+1,w1,w2); if(!w1) { mi=100000000; for(int i=1;i<=4;i++) mi=min(mi,dp(a,b,c,d,i,w2)); ans+=mi/(54-n); } if(!w2) { mi=100000000; for(int i=1;i<=4;i++) mi=min(mi,dp(a,b,c,d,w1,i)); ans+=mi/(54-n); } return f[a][b][c][d][w1][w2]=ans; } int main() { int mo=0; for(int a=0;a<=13;a++) for(int b=0;b<=13;b++) for(int c=0;c<=13;c++) for(int d=0;d<=13;d++) for(int w1=0;w1<=4;w1++) for(int w2=0;w2<=4;w2++) f[a][b][c][d][w1][w2]=-1; scanf("%d%d%d%d",&A,&B,&C,&D); if(A>13) mo+=A-13; if(B>13) mo+=B-13; if(C>13) mo+=C-13; if(D>13) mo+=D-13; if(mo>2) { printf("-1.000"); return 0; } double res=dp(0,0,0,0,0,0); printf("%.3lf",res); return 0; }