题目链接:点击打开链接
题意:
给定13张各不相同的扑克牌,问最少需要几手打出
每手打出的牌必须符合以下任意标准之一:
1、任意单张
2、相同数字2张
3、相同数字3张
4、相同数字4张
5、相同数字3张+相同数字2张
6、连续5个及5个以上的数字
思路:
状压dp,dp[i]表示选了i的状态的最小牌数
然后要预处理出能一次打出的状态,这样不会t。。
#include
#include
#include
#include
#include
#include
using namespace std; #define inf 1000000 #define maxn (1<<13) struct node{ int num; char c; void put(){ if(num==14)printf("A"); else if(2<= num && num <= 9) printf("%d",num); else if(num==10)printf("T"); else if(num == 11)printf("J"); else if(num==12)printf("Q"); else printf("K"); printf("%c",c); } }a[15]; void put(int u){ for(int i = 0; i < 13 && u; i++){ if(u&1) { a[i].put(); u>>=1; u ? printf(" ") : puts(""); } else u>>=1; } } int dp[maxn], pre[maxn], all; int Stack[20], top; void siz(int x){ top = 0; for(int i = 0; i < 13 && x; i++) { if(x&1) Stack[top++] = i; x>>=1; } } int vis[15]; int ok(int u){ siz(u); memset(vis, 0, sizeof vis); int dui = 0, fir= 15, ed = 0; for(int i = 0; i < top; i++) { if(vis[ a[Stack[i]].num ]==0) { dui++; } vis[ a[Stack[i]].num ] ++; fir = min(fir, a[Stack[i]].num); ed = max(ed, a[Stack[i]].num); } if(dui==1 && top<=4) return 1; if(top == 5 && dui==2) { if(vis[fir] ==4 || vis[ed] == 4)return -1; return 1; } if(top>=5 && dui==top && (dui == (ed-fir+1))) return 1; return -1; } vector
G; int dfs(int u){ if(dp[u]!=-1) return dp[u]; int ans = inf; for(int i = 0; i < G.size(); i++) { int v = G[i]; if((v&u)==v) { int tmp = dfs(u^v) +1; if(ans>tmp) pre[u] = u^v, ans = tmp; } } return dp[u] = ans; } int main() { int T;scanf("%d",&T); all = maxn-1; while( T--) { for(int i = 0; i < 13; i++) { char s[10]; scanf("%s",s); if(s[0]=='A')a[i].num = 14; else if('2' <= s[0] &&s[0]<='9') a[i].num = s[0]-'0'; else if(s[0]=='T') a[i].num = 10; else if(s[0]=='J') a[i].num = 11; else if(s[0]=='Q') a[i].num = 12; else a[i].num = 13; a[i].c = s[1]; } dp[0] = 0; G.clear(); for(int i = 1; i <= all; i++) { dp[i] = ok(i); if(dp[i]==1)G.push_back(i); } memset(pre, -1, sizeof pre); cout<