【dfs+贪心】【cofun1624】斗地主
2017-10-13 20:59
351 查看
【cofun1624】斗地主
DescriptionInput Format
输入文件名为 landlords.in。
第一行包含用空格隔开的2个正整数T,n,表示手牌的组数以及每组手牌的张数。
接下来T组数据,每组数据n行,每行一个非负整数对ai,bi,表示一张牌,其中ai表示牌的数码,bi表示牌的花色,中间用空格隔开。特别的,我们用 1 来表示数码 A,11 表示数码 J,12 表示数码 Q,13 表示数码 K;黑桃、红心、梅花、方片分别用 1-4 来表示;小王的表示方法为 0 1,大王的表示方法为 0 2。
Output Format
输出文件名为 landlords.out。 共 T 行,每行一个整数,表示打光第i组手牌的最少次数。
Sample Input
【输入样例 1】
1 8
7 4
8 4
9 1
10 4
11 1
5 1
1 4
1 1
【输入样例 2】
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
Sample Output
输出样例 1
3
输出样例 2
6
【输入输出样例 1 说明】
共有 1 组手牌,包含 8 张牌:方片7,方片8,黑桃9,方片10,黑桃J,黑桃5,方片A 以及黑桃A。可以通过打单顺子(方片7,方片8,黑桃9,方片10,黑桃J),单张牌(黑桃5)以及对子牌(黑桃A 以及方片A)在3次内打光。
Hint
分析:
可以把王炸视为对子,因此花色与问题本身并无关系,牌类种数<=14。
显然只有顺子对出牌顺序产生影响,而三张、对子、单张可以贪心出最少的出牌数。
考虑爆搜+剪枝。
dfs减去顺子.
剪枝中贪心出其他的出牌数,加上当前步数若> ans,则直接 return.
具体实现见代码→
代码:
#include <bits/stdc++.h> using namespace std; int T, n, a, b, i, num[15], cou[15], ans; inline int tan() { memset(cou, 0, sizeof(cou)); int t = 0; for(int i = 1; i <= 14; i ++) cou[num[i]] ++; if (cou[4] && (cou[2] > 1 || cou[1] > 1)) { if (cou[2] / 2 <= cou[4]) t += cou[2] / 2, cou[4] -= cou[2] / 2, cou[2] %= 2; else t += cou[4], cou[2] -= cou[4] * 2, cou[4] = 0;//四带二对子 if (cou[1] / 2 <= cou[4]) t += cou[1] / 2, cou[4] -= cou[1] / 2, cou[1] %= 2; else t += cou[4], cou[1] -= cou[4] * 2, cou[4] = 0;//四带二单牌 } if (cou[3] && (cou[2] || cou[1])) { if (cou[2] <= cou[3]) t += cou[2], cou[3] -= cou[2], cou[2] = 0; else t += cou[3], cou[2] -= cou[3], cou[3] = 0;//三带二 if (cou[1] <= cou[3]) t += cou[1], cou[3] -= cou[1], cou[1] = 0; else t += cou[3], cou[1] -= cou[3], cou[3] = 0;//三带一 } t += cou[4] + cou[3] + cou[2] + cou[1];//炸弹&三张牌&对子牌&单张牌 return t; } //贪心出打完各种牌的最少次数 inline void dfs(int s) { if (s > ans) return; ans = min(ans, s + tan()); int i, j, k, l; for(i = 3; i <= 13; i ++) { for(j = i; num[j] >= 3; j ++); if (j - i < 2) continue; for(k = i + 1; k < j; k ++) { for(l = i; l <= k; l ++) num[l] -= 3; dfs(s + 1); for(l = i; l <= k; l ++) num[l] += 3; } }//三顺子 for(i = 3; i <= 12; i ++) { for(j = i; num[j] >= 2; j ++); if (j - i < 3) continue; for(k = i + 2; k < j; k ++) { for(l = i; l <= k; l ++) num[l] -= 2; dfs(s + 1); for(l = i; l <= k; l ++) num[l] += 2; } }//二顺子 for(i = 3; i <= 10; i ++) { for(j = i; num[j] >= 1; j ++); if (j - i < 5) continue; for(k = i + 4; k < j; k ++) { for(l = i; l <= k; l ++) num[l] --; dfs(s + 1); for(l = i; l <= k; l ++) num[l] ++; } }//单顺子 return; } //搜索打出顺子 int main() { for(scanf("%d%d", &T, &n); T; T --) { memset(num, 0, sizeof(num)); ans = 0; //初始化 for(i = 1; i <= n; i ++) { scanf("%d%d", &a, &b); if (a == 1) a = 14; if (a == 0) a = 1; num[a] ++; ans ++; } //预处理牌,花色无用 dfs(0); //爆搜 printf("%d\n", ans); } return 0; }
【老师在讲初赛的题目QAQ做不下去题目,来啪啪题解。
这题被cofun归在状压DP中,还蛮奇怪的233是因为有状压的做法吗?把各种打牌顺序压位,把牌的情况压位,把一种牌的张数另存?貌似可行??ε=(´ο`*)))唉其实搜索和DP相似之处好多,比如都有状态,都要转移,而且很多hash还蛮像【??】
2333坐等放学~
相关文章推荐
- [noip2015]斗地主(dfs+贪心)
- NOIP2015斗地主[DFS 贪心]
- POJ 2718 Smallest Difference(DFS或者贪心)
- 【codeforces 680 D】【数学+贪心+DFS】【求一个不超过 m 的最大体积 X, 每次选一个最大的 x 使得 x3 不超过当前剩余体积。问在能选最多个数的情况下,X 最大是多少】
- 【NOIp 2015】【DFS】斗地主
- Codeforces 680D Bear and Tower of Cubes 贪心 DFS
- NOIP2010 引水入城 贪心+DFS
- 【Codeforces Round 328 (Div 2)D】【树的直径 树的重心 贪心 两次dfs都找最小编号最远点】Super M 经过树上所有重要点的最小距离
- (noip 2015 斗地主)<搜索+贪心>
- 【codeforces 731C 】【并查集+贪心 或者dfs搞连通分支 】【有n只袜子,k种颜色,在m天中,左右脚分别穿下标为l,r的袜子,问最少修改几只袜子颜色,可以使每天穿的袜子左右两只都同色】
- bzoj 4325: NOIP2015 斗地主 (dfs+剪枝)
- 洛谷 2279 [HNOI2003] 消防局的设立 贪心+dfs
- UVA 10123 No Tipping (物理+贪心+DFS剪枝)
- [NOIP模拟题][Catalan数][逆元][贪心][线段树][DFS][搜索顺序剪枝]
- CF 782C 贪心,DFS染色,水题
- CF - 782D. Innokenty and a Football League - 模拟+思维+贪心+dfs插入
- HDU-5802-Windows 10-贪心+dfs
- 2015多校第6场 HDU 5355 Cake 贪心,暴力DFS
- [CF430C]Xor-tree(DFS,贪心)
- hdu 4274 Spy's Work DFS 贪心