1. 程式人生 > >[NOIP 2015] 鬥地主

[NOIP 2015] 鬥地主

http c++ += std line lin 進制 pre def

[題目鏈接]

http://uoj.ac/problem/147

[算法]

搜索,對於每一種狀態,我們可以將其壓縮成一個五進制數,用STL-map記錄在其狀態下的最少出牌次數

在搜索時,我們可以采取一個優化 : 如果只剩下單牌,那麽直接將單牌出完

[代碼]

#include<bits/stdc++.h>
using namespace std;
#define MAXN 25
#define MAXT 10
#define MAXC 15
const int inf = 2e9;

int T,n;
int cnt[MAXC + 1
]; map<long long,int> mp; inline long long get_state() { long long ret = 0; for (int i = 1; i <= 15; i++) ret = 1ll * ret * 5 + 1ll * cnt[i]; return ret; } inline int dfs() { int step = inf; long long state = get_state(); bool flag = false; if (state == 0
) return 0; if (mp.count(state)) return mp[state]; for (int i = 1; i <= 11; i++) { if (cnt[i] >= 3 && cnt[i + 1] >= 3) { for (int j = i + 1; j <= 12; j++) {
if (cnt[j] >= 3) { for (int k = i; k <= j; k++) cnt[k] -= 3; step = min(step,dfs() + 1); flag = true; for (int k = i; k <= j; k++) cnt[k] += 3; } else break; } } } for (int i = 1; i <= 10; i++) { if (cnt[i] >= 2 && cnt[i + 1] >= 2 && cnt[i + 2] >= 2) { for (int j = i + 2; j <= 12; j++) { if (cnt[j] >= 2) { for (int k = i; k <= j; k++) cnt[k] -= 2; step = min(step,dfs() + 1); flag = true; for (int k = i; k <= j; k++) cnt[k] += 2; } else break; } } } for (int i = 1; i <= 8; i++) { if (cnt[i] >= 1 && cnt[i + 1] >= 1 && cnt[i + 2] >= 1 && cnt[i + 3] >= 1 && cnt[i + 4] >= 1) { for (int j = i + 4; j <= 12; j++) { if (cnt[j] >= 1) { for (int k = i; k <= j; k++) cnt[k]--; flag = true; step = min(step,dfs() + 1); for (int k = i; k <= j; k++) cnt[k]++; } else break; } } } for (int i = 1; i <= 13; i++) { if (cnt[i] >= 4) { cnt[i] -= 4; for (int j = 1; j <= 15; j++) { if (!cnt[j]) continue; cnt[j]--; for (int k = 1; k <= 15; k++) { if (!cnt[k]) continue; cnt[k]--; flag = true; step = min(step,dfs() + 1); cnt[k]++; } cnt[j]++; } for (int j = 1; j <= 15; j++) { if (cnt[j] < 2) continue; cnt[j] -= 2; for (int k = 1; k <= 15; k++) { if (cnt[k] < 2) continue; cnt[k] -= 2; flag = true; step = min(step,dfs() + 1); cnt[k] += 2; } cnt[j] += 2; } cnt[i] += 4; } } for (int i = 1; i <= 13; i++) { if (cnt[i] >= 3) { cnt[i] -= 3; for (int j = 1; j <= 13; j++) { if (cnt[j] >= 2) { cnt[j] -= 2; flag = true; step = min(step,dfs() + 1); cnt[j] += 2; } } cnt[i] += 3; } } for (int i = 1; i <= 13; i++) { if (cnt[i] >= 3) { cnt[i] -= 3; for (int j = 1; j <= 15; j++) { if (cnt[j] >= 1) { cnt[j]--; flag = true; step = min(step,dfs() + 1); cnt[j]++; } } cnt[i] += 3; } } for (int i = 1; i <= 13; i++) { if (cnt[i] >= 4) { cnt[i] -= 4; flag = true; step = min(step,dfs() + 1); cnt[i] += 4; } } for (int i = 1; i <= 13; i++) { if (cnt[i] >= 3) { cnt[i] -= 3; flag = true; step = min(step,dfs() + 1); cnt[i] += 3; } } for (int i = 1; i <= 13; i++) { if (cnt[i] >= 2) { cnt[i] -= 2; flag = true; step = min(step,dfs() + 1); cnt[i] += 2; } } if (cnt[14] >= 1 && cnt[15] >= 1) { cnt[14]--; cnt[15]--; flag = true; step = min(step,dfs() + 1); cnt[14]++; cnt[15]++; } if (!flag) { step = 0; for (int i = 1; i <= 15; i++) step += cnt[i]; } return mp[state] = step; } int main() { scanf("%d%d",&T,&n); mp.clear(); while (T--) { memset(cnt,0,sizeof(cnt)); for (int i = 1; i <= n; i++) { int a,b; scanf("%d%d",&a,&b); if (a == 0 && b == 1) cnt[14]++; else if (a == 0 && b == 2) cnt[15]++; else if (a == 2) cnt[13]++; else if (a == 1) cnt[12]++; else cnt[a - 2]++; } printf("%d\n",dfs()); mp.clear(); } return 0; }

[NOIP 2015] 鬥地主