【NOIP2015】斗地主(dfs)
练练码力。
如果没有顺子,显然最小出牌次数可以贪心,优先出四带二,然后三带一或三带二,最后出对拍和单牌。
把大小王归到单排一类中,最后特判如果剩余的单排大于2,把这两张当成大小王一起出。
枚举所有出顺子的情况,用三个dfs,其中:
dfs(int now, int l, int tot, int times)
//now 当前到了第几小的牌
//l 当前顺子的长度
//tot 当前已经出了几次牌
//times 当前大小的顺子(三顺,二顺,单顺)重复搜索了几遍
关于为什么要用用times记录并重复搜索:
考虑这组牌
显然答案为两次,分别是3到7,6到10,中间有重复的部分,所以需要重复搜索。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
const int N = 30;
const int h[] = {14, 12, 13, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
int n, ans = 1e9;
int card[N];
bool flag = false;
void check(int tt) {
int t[5]; memset(t, 0, sizeof(t));
for(int i = 1; i <= 15; i++) {
t[card[i]]++;
}
while(t[4]) {
if(t[1] >= 2) {
t[4]--; t[1] -= 2; tt++; continue;
} else if(t[2] >= 2) {
t[4]--; t[2] -= 2; tt++; continue;
} else if(t[2] >= 1) {
t[4]--; t[2]--; tt++; continue;
} else {
t[4]--; tt++; continue;
}
}
while(t[3]) {
if(t[1] >= 1) {
t[3]--; t[1]--; tt++; continue;
} else if(t[2] >= 1) {
t[3]--; t[2]--; tt++; continue;
} else {
t[3]--; tt++; continue;
}
}
while(t[2]) tt++, t[2]--;
if(flag && t[1] >= 2) {
t[1] -= 2; tt++;
}
tt += t[1];
ans = min(ans, tt);
return ;
}
void dfs2(int now, int l, int tot, int times) {
if(now == 13) {
if(l >= 5) {
if(times < 4) dfs2(1, 0, tot + 1, times + 1);
if(times == 4) check(tot + 1);
}
else if(l == 0) {
if(times < 4) dfs2(1, 0, tot, times + 1);
if(times == 4) check(tot);
}
return ;
}
if(card[now] >= 1) {
card[now] -= 1;
dfs2(now + 1, l + 1, tot, times);
card[now] += 1;
if(l >= 5) dfs2(now + 1, 0, tot + 1, times);
} else {
if(l >= 5) dfs2(now + 1, 0, tot + 1, times);
}
if(l == 0) dfs2(now + 1, 0, tot, times);
}
void dfs1(int now, int l, int tot, int times) {//2
if(now == 13) {
if(l >= 3) {
if(times < 4) dfs1(1, 0, tot + 1, times + 1);
if(times == 4) dfs2(1, 0, tot + 1, 0);
}
else if(l == 0) {
if(times < 4) dfs1(1, 0, tot, times + 1);
if(times == 4) dfs2(1, 0, tot, 0);
}
return ;
}
if(card[now] >= 2) {
card[now] -= 2;
dfs1(now + 1, l + 1, tot, times);
card[now] += 2;
if(l >= 3) dfs1(now + 1, 0, tot + 1, times);
} else {
if(l >= 3) dfs1(now + 1, 0, tot + 1, times);
}
if(l == 0) dfs1(now + 1, 0, tot, times);
}
void dfs(int now, int l, int tot, int times) {//3
if(now == 13) {
if(l >= 2) {
if(times < 4) dfs(1, 0, tot + 1, times + 1);
if(times == 4) dfs1(1, 0, tot + 1, 0);
}
else if(l == 0) {
if(times < 4) dfs(1, 0, tot, times + 1);
if(times == 4) dfs1(1, 0, tot, 0);
}
return ;
}
if(card[now] >= 3) {
card[now] -= 3;
dfs(now + 1, l + 1, tot, times);
card[now] += 3;
if(l >= 2) dfs(now + 1, 0, tot + 1, times);
} else {
if(l >= 2) dfs(now + 1, 0, tot + 1, times);
}
if(l == 0) dfs(now + 1, 0, tot, times);
}
int main() {
// freopen("data.in", "r", stdin);
int T; scanf("%d%d", &T, &n);
while(T--) {
memset(card, 0, sizeof(card));
ans = n; flag = false;
for(int i = 1, x, y; i <= n; i++) {
scanf("%d%d", &x, &y);
if(x == 0 && y == 1) card[14]++;
else if(x == 0 && y == 2) card[15]++;
else card[h[x]]++;
}
if(card[14] && card[15]) flag = true;
dfs(1, 0, 0, 0);
printf("%d\n", ans);
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】