1 solutions
-
0
直接搜索会导致超时,因为可以选择的数量太多了,那么我们可以将所有的牌分成两类(顺子和非顺子),梳子需要考虑牌的顺序,而非顺子不需要考虑牌的顺序,只需要考虑对应的牌的数量就可以了。
#include<bits/stdc++.h> using namespace std; const int INF=100; int f[24][12][8][6]; int dp(int s[]) { int sum=0; for(int i=1;i<=4;i++) //枚举每类牌 { if(s[i]<0) //不合法的序列 { return INF; } else { sum+=s[i]; } } int& v=f[s[1]][s[2]][s[3]][s[4]]; if(v!=-1) return v; //已经找到过 if(!sum) return v=0; //已经出完 v=INF; for(int k=1;k<=4;k++) //枚举出牌 { for(int i=k;i<=4;i++) //从哪里出 { s[i]--,s[i-k]++; //出了以后的变化 v=min(v,dp(s)+1); //更新答案 if(k==3) //3带 { for(int x=1;x<=2;x++) { for(int y=x;y<=4;y++) { s[y]--,s[y-x]++; v=min(v,dp(s)+1); s[y]++,s[y-x]--; } } } else if(k==4) //4带 { for(int x=1;x<=2;x++) { for(int y=x;y<=4;y++) { for(int z=x;z<=4;z++) { s[y]--,s[y-x]++; s[z]--,s[z-x]++; v=min(v,dp(s)+1); s[y]++,s[y-x]--; s[z]++,s[z-x]--; } } } } s[i]++,s[i-k]--; } } return v; } bool check(int c[],int l,int r,int k) //判断是否可以出 { for(int i=l;i<=r;i++) { if(c[i]<k) { return false; } } return true; } void add(int c[],int l,int r,int k) //范围变化 { for(int i=l;i<=r;i++) { c[i]+=k; } } int dfs(int c[]) //搜索 { for(int i=0;i<14;i++) //非法状态 { if(c[i]<0) { return INF; } } int s[5]={0}; for(int i=0;i<14;i++) //统计数量 { s[c[i]]++; } int res=dp(s); //不用顺子 int len[]={0,5,3,2}; for(int k=1;k<=3;k++) //顺子类别 { for(int i=2;i<=13;i++) //起点 { for(int j=i+1;j<=13;j++) //终点 { if(j-i+1>=len[k]&&check(c,i,j,k)) { add(c,i,j,-k); res=min(res,dfs(c)+1); add(c,i,j,k); } } } } return res; } int main() { memset(f,-1,sizeof f); int T,n; cin>>T>>n; while(T--) { int cnt[14]={0}; for(int i=0;i<n;i++) { int a,b; cin>>a>>b; if(a==1) a=13; //a变成k的后面 else if(a) a--; //其它前移一次 cnt[a]++; //统计对应牌的数量 } cout<<dfs(cnt)<<endl; } return 0; }
- 1
Information
- ID
- 1114
- Time
- 1000ms
- Memory
- 256MiB
- Difficulty
- 10
- Tags
- # Submissions
- 1
- Accepted
- 1
- Uploaded By