UOJ 147|NOIP 2015|斗地主|搜索|贪心

来源:互联网 发布:软件开发标准流程 编辑:程序博客网 时间:2024/05/21 17:45

你有一些扑克牌,有一些出牌方式,问最少出多少张牌才能全部打光。
分别有:王炸、炸弹、单张、对子、三张、三带一、三带二、四带两张、四带两对、单顺子、双顺子、三顺子。
顺子不包含大小王和2。

题目:http://uoj.ac/problem/147

没有飞机真是可惜,欢乐斗地主的飞机很爽的说
UOJ中途加强数据QwQ。

嘛,考虑搜索。
(还记得考场上的程序写的很丑)

显然对于一个出牌的方案,顺序是无关的,因此考虑优先出顺子,顺子出的牌最多是原因之一。
dfs搜索出顺子的方案。
那么对于每种出顺子的方案,我们可以知道还剩哪些牌,本着多出牌的原则,考虑四张和三张的牌带其他1张2张的牌出掉即可:依次出掉四带两对、四带两张、三带二、三带一,最后再出单种牌(1~4张)。
当然按照这个顺序出牌就不会出现某种牌有4张但一次只出掉3张的情况,带的对子和单牌也是,即每种牌只会一次全部出完。
然后贪心无法处理(感觉是这样?)顺子,所以必须搜顺子。

然后就没啥了。
最优性剪枝是照例有的。

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;#define FOR(i,j,k) for(int i=j;i<=k;i++)#define FORD(i,j,k) for(int i=j;i>=k;i--)const int card[] = {0, 4, 2, 1};int a[16], b[16], ans;int sum() {#define p(i,x,j,y) while (b[i] >= x && b[j] >= y) b[i] -= x, b[j] -= y, ++s    int s = 0;    memset(b, 0, sizeof b);    FOR(i,0,14) if (i != 1) ++b[a[i]];    p(4, 1, 2, 2); p(4, 1, 1, 2); p(3, 1, 2, 1); p(3, 1, 1, 1);    return s + b[4] + b[3] + b[2] + b[1];}void dfs(int dep) {    if (dep >= ans) return;    int j;    FORD(x,3,1) FOR(i,3,13) {        for (j = i; j <= 14 && a[j] >= x; j++);        int len = (--j) - i + 1;        if (len > card[x]) {            FOR(k,i,i+card[x]-1) a[k] -= x;            FOR(k,i+card[x],j) a[k] -= x, dfs(dep + 1);            FOR(k,i,j) a[k] += x;        }    }    ans = min(ans, dep + sum());}int main() {    int t, n, x, y;    scanf("%d%d", &t, &n);    while (t--) {        memset(a, 0, sizeof a);        FOR(i,1,n) {            scanf("%d%d", &x, &y);            if (x == 1) x = 14;            ++a[x];        }        ans = min(n, 13);        dfs(0);        printf("%d\n", ans);    }    return 0;}
0 0
原创粉丝点击