样例过不了, 但是22pts

P2540 [NOIP2015 提高组] 斗地主 加强版

48pts了 ```cpp #include <bits/stdc++.h> using namespace std; inline int read() { int s = 0, w = 1;char ch = getchar(); while(ch < '0' || ch > '9'){if(ch == '-') w = -1;ch = getchar();} while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0';ch = getchar();} return s * w; } int T, n, a[16], ans = 0x3f3f3f; inline void dfs(int step, int sum) { if(step >= ans) return ; if(sum > n) return ; if(sum == n) { ans = min(step, ans); return ; } for(int i = 2;i <= 15;i ++) { if(a[i] >= 4) { a[i] -= 4; for(int j = 2;j <= 15;j ++) { if(i == j) continue; if(a[j] >= 1) { a[j] -= 1; for(int k = 2;k <= 15;k ++) { if(k == i) continue; if(a[k] >= 1) { a[k] --; dfs(step + 1, sum + 6); a[k] ++; } } a[j] ++; }//四带二单 if(a[j] >= 2 && j != 15) { a[j] -= 2; for(int k = 2;k <= 14;k ++) { if(k == i) continue; if(a[k] >= 2) { a[k] -= 2; dfs(step + 1, sum + 8); a[k] += 2; } } a[j] += 2;//四带二对 } } dfs(step + 1, sum + 4);//炸弹 a[i] += 4; } if(i != 2 && i != 15) { if(a[i] >= 3) { a[i] -= 3; int y = 1; for(int j = i + 1;j <= 14;j ++) if(a[j] >= 3) y ++; else break; if(y >= 2) { for(int j = i + 1;j <= i + y - 1;j ++) a[j] -= 3; dfs(step + 1, sum + y * 3); for(int j = i + 1;j <= i + y - 1;j ++) a[j] += 3; } a[i] += 3;//三顺子 } else if(a[i] >= 2) { a[i] -= 2; int y = 1; for(int j = i + 1;j <= 14;j ++) if(a[j] >= 2) y ++; else break; if(y >= 3) { for(int j = i + 1;j <= i + y - 1;j ++) a[j] -= 2; dfs(step + 1, sum + y * 2); for(int j = i + 1;j <= i + y - 1;j ++) a[j] += 2; } a[i] += 2;//双顺子 } else if(a[i] >= 1) { a[i] --; int y = 1; for(int j = i + 1;j <= 14;j ++) if(a[j] >= 1) y ++; else break; if(y >= 5) { for(int j = i + 1;j <= i + y - 1;j ++) a[j] --; dfs(step + 1, sum + y); for(int j = i + 1;j <= i + y - 1;j ++) a[j] ++; } a[i] ++;//单顺子 } } if(a[i] >= 3) { a[i] -= 3; for(int j = 2;j <= 15;j ++) { if(i == j) continue; if(a[j] >= 2 && j != 15) { a[j] -= 2; dfs(step + 1, sum + 5); a[j] += 2;//三带二 } if(a[j] >= 1) { a[j] --; dfs(step + 1, sum + 4); a[j] ++;//三带一 } } dfs(step + 1, sum + 3);//三张牌 a[i] += 3; } if(a[i] >= 2) { a[i] -= 2; dfs(step + 1, sum + 2); a[i] += 2; }//对子 if(a[i] >= 1) { a[i] --; dfs(step + 1, sum + 1); a[i] ++; }//单张 } } int main() { T = read(), n = read(); while(T --) { for(int i = 1;i <= n;i ++) { int x = read(), y = read(); if(x == 0) a[15] ++; else if(x == 1) a[14] ++; else a[x] ++; } dfs(0, 0); cout << ans << endl; for(int i = 1;i <= 15;i ++) a[i] = 0; ans = 0x3f3f3f; } return 0; } ``` ~~验证码tkkk寄~~
by Killua_Zaoldyeck @ 2023-07-12 16:27:25


@[5k_sync_closer](/user/388651) 5k救我!
by Killua_Zaoldyeck @ 2023-07-12 16:53:51


不调大模拟
by 5k_sync_closer @ 2023-07-12 16:54:36


@[5k_sync_closer](/user/388651) 恼
by Killua_Zaoldyeck @ 2023-07-12 16:59:29


@[02yyds](/user/728127) 调好了,改了一大堆东西,顺便把TLE搞没了 ```cpp #include <bits/stdc++.h> using namespace std; inline int read() { int s = 0, w = 1;char ch = getchar(); while(ch < '0' || ch > '9'){if(ch == '-') w = -1;ch = getchar();} while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0';ch = getchar();} return s * w; } int T, n, a[16], ans = 0x3f3f3f,b[101][25],vis[101]; inline void dfs(int step) { if(step >= ans) return ; for(int i = 2;i <= 15;i ++) { if(a[i] >= 4) { a[i] -= 4; for(int j = 2;j <= 15;j ++) { if(i == j) continue; if(a[j] >= 1) { a[j] --; for(int k = 2;k <= 15;k ++) { if(k == i) continue; if(a[k] >= 1) { a[k] --; dfs(step + 1); a[k] ++; } } a[j] ++; }//四带二单 if(a[j] >= 2 && j != 15) { a[j] -= 2; for(int k = 2;k <= 14;k ++) { if(k == i) continue; if(a[k] >= 2) { a[k] -= 2; dfs(step + 1); a[k] += 2; } } a[j] += 2;//四带二对 } } a[i] += 4; } if(a[i] >= 3 && i!=2 && i!=15) { a[i] -= 3; int y = 1; for(int j = i + 1;j <= 14;j ++) { if(a[j] >= 3) y ++; else break; if(y >= 2) { for(int j = i + 1;j <= i + y - 1;j ++) a[j] -= 3; dfs(step + 1); for(int j = i + 1;j <= i + y - 1;j ++) a[j] += 3; } } a[i] += 3;//三顺子 } if(a[i] >= 2 && i!=2 && i!=15) { a[i] -= 2; int y = 1; for(int j = i + 1;j <= 14;j ++) { if(a[j] >= 2) y ++; else break; if(y >= 3) { for(int j = i + 1;j <= i + y - 1;j ++) a[j] -= 2; dfs(step + 1); for(int j = i + 1;j <= i + y - 1;j ++) a[j] += 2; } } a[i] += 2;//双顺子 } if(a[i] >= 1 && i!=2 && i!=15) { a[i] --; int y = 1; for(int j = i + 1;j <= 14;j ++) { if(a[j] >= 1) y ++; else break; if(y >= 5) { for(int j = i + 1;j <= i + y - 1;j ++) a[j] --; dfs(step + 1); for(int j = i + 1;j <= i + y - 1;j ++) a[j] ++; } } a[i] ++;//单顺子 } if(a[i] >= 3) { a[i] -= 3; for(int j = 2;j <= 15;j ++) { if(i == j) continue; if(a[j] >= 2 && j != 15) { a[j] -= 2; dfs(step + 1); a[j] += 2;//三带二 } if(a[j] >= 1) { a[j] --; dfs(step + 1); a[j] ++;//三带一 } } a[i] += 3; } } for(int i=2;i<=15;i++) if(a[i]) step++; ans=min(step,ans); } int main() { T = read(), n = read(); int st=T; while(T --) { for(int i = 1;i <= 15;i ++)a[i] = 0; for(int i = 1;i <= n;i ++) { int x = read(), y = read(); if(x == 0) b[T+1][15]++,a[15] ++; else if(x == 1) b[T+1][14]++,a[14] ++; else a[x] ++,b[T+1][x]++; } int flag=0; for(int i=st;i>T+1;i--) { bool y=true; for(int j=2;j<=15;j++) if(b[i][j]!=a[j]) { y=false; break; } if(y) { flag=i; break; } } if(flag) cout<<vis[flag]<<endl; else { dfs(0); vis[T+1]=ans; cout<<ans<<endl; } ans = 0x3f3f3f; } return 0; } ``` 主要的问题: 1.顺子不要用if...else if...连起来,每种顺子都要枚举。 2.顺子不能用2。 3.不用记录用了几张,因为1张2张3张4张都可以直接出,所以最后直接将这些牌都出掉,不需要再递归,还少了一个变量。 ```cpp for(int i=2;i<=15;i++) if(a[i]) step++; ``` 优化: 加了一个类似记忆化的数组,因为#25的数据长这样: ``` 10 23 12 1 11 4 5 3 10 4 4 2 12 3 6 4 8 3 10 2 12 4 9 1 6 1 4 1 8 4 7 3 6 3 7 1 4 4 7 2 0 2 8 1 1 3 6 2 12 1 ...... ``` out ``` 5 5 5 5 5 5 5 5 5 5 ``` 这是一模一样的10个数据
by qiuqiuqzm @ 2023-07-18 17:38:28


@[qiuqiuqzm](/user/658945) 謝謝,關注了
by Killua_Zaoldyeck @ 2023-07-18 17:58:40


|