-
- 291通過
- 2.5K提交
- 題目提供者洛谷OnlineJudge
- 標簽搜索/枚舉2015NOIp提高組
- 難度提高+/省選-
最新討論
題目描述
牛牛最近迷上了一種叫斗地主的撲克游戲。斗地主是一種使用黑桃、紅心、梅花、方片的A到K加上大小王的共54張牌來進行的撲克牌游戲。在斗地主中,牌的大小關系根據牌的數碼表示如下:3<4<5<6<7<8<9<10<J<Q<K<A<2<小王<大王,而花色並不對牌的大小產生影響。每一局游戲中,一副手牌由n張牌組成。游戲者每次可以根據規定的牌型進行出牌,首先打光自己的手牌一方取得游戲的勝利。
現在,牛牛只想知道,對於自己的若干組手牌,分別最少需要多少次出牌可以將它們打光。請你幫他解決這個問題。
需要注意的是,本題中游戲者每次可以出手的牌型與一般的斗地主相似而略有不同。
具體規則如下:
輸入輸出格式
輸入格式:
第一行包含用空格隔開的2個正整數Tn,表示手牌的組數以及每組手牌的張數。
接下來T組數據,每組數據n行,每行一個非負整數對aibi表示一張牌,其中ai示牌的數碼,bi表示牌的花色,中間用空格隔開。特別的,我們用1來表示數碼A,11表示數碼J,12表示數碼Q,13表示數碼K;黑桃、紅心、梅花、方片分別用1-4來表示;小王的表示方法為01,大王的表示方法為02。
輸出格式:
共T行,每行一個整數,表示打光第i手牌的最少次數。
輸入輸出樣例
1 8 7 4 8 4 9 1 10 4 11 1 5 1 1 4 1 1
3
1 17 12 3 4 3 2 3 5 4 10 2 3 3 12 2 0 1 1 3 10 1 6 2 12 1 11 3 5 2 12 4 2 2 7 2
6
說明
樣例1說明
共有1組手牌,包含8張牌:方片7,方片8,黑桃9,方片10,黑桃J,黑桃5,方片A以及黑桃A。可以通過打單順子(方片7,方片8,黑桃9,方片10,黑桃J),單張牌(黑桃5)以及對子牌(黑桃A以及方片A)在3次內打光。
對於不同的測試點, 我們約定手牌組數T與張數n的規模如下:
數據保證:所有的手牌都是隨機生成的。
分析:重新做這道題,滿滿都是淚啊,在考場上打了個30分暴力,結果爆0了......步入正題,這道題一看就知道肯定是爆搜,但是情況實在太多,怎么辦?注意到對次數有影響的就是順子,如果不打順子,那么最少的出牌次數是一定的,所以dfs搜索出三順子二順子和順子后的總步數,然后更新答案即可.花色在本題中無用.
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn = 25; int a[maxn], num[maxn]; int n, t, ans; int chupai() { memset(num, 0, sizeof(num)); for (int i = 0; i <= 13; i++) num[a[i]]++; int tot = 0; while (num[4] && num[2] > 1) { num[4]--; num[2] -= 2; tot++; } while (num[4] && num[1] > 1) { num[4]--; num[1] -= 2; tot++; } while (num[4] && num[2]) { num[4]--; num[2]--; tot++; } while (num[3] && num[2]) { num[3]--; num[2]--; tot++; } while (num[3] && num[1]) { num[3]--; num[1]--; tot++; } return tot + num[1] + num[2] + num[3] + num[4]; } void dfs(int step) { if (step >= ans) return; int temp = chupai(); if (temp + step < ans) ans = temp + step; for (int i = 2; i <= 13; i++) { int j = i; while (a[j] >= 3) j++; if (j - i >= 2) { for (int j2 = i + 1; j2 <= j - 1; j2++) { for (int k = i; k <= j2; k++) a[k] -= 3; dfs(step + 1); for (int k = i; k <= j2; k++) a[k] += 3; } } } for (int i = 2; i <= 13; i++) { int j = i; while (a[j] >= 2) j++; if (j - i >= 3) { for (int j2 = i + 2; j2 <= j - 1; j2++) { for (int k = i; k <= j2; k++) a[k] -= 2; dfs(step + 1); for (int k = i; k <= j2; k++) a[k] += 2; } } } for (int i = 2; i <= 13; i++) { int j = i; while (a[j] >= 1) j++; if (j - i >= 5) { for (int j2 = i + 4; j2 <= j - 1; j2++) { for (int k = i; k <= j2; k++) a[k]--; dfs(step + 1); for (int k = i; k <= j2; k++) a[k]++; } } } } int main() { scanf("%d%d", &t, &n); while (t--) { memset(a, 0, sizeof(a)); for (int i = 1; i <= n; i++) { int x, y; scanf("%d%d", &x, &y); if (x == 1) //轉換掉A x = 13; else if (x) x--; a[x]++; } ans = 1e9; dfs(0); printf("%d\n", ans); } return 0; }