斗地主
题解:
一开始拿到这道题觉得是DP什么的,然后后面的同学们纷纷说着什么五进制压位DP,……,那个DP思想是很好理解的,内存1个G好像也可以……
等等,内存1个G的话干嘛不深搜?直接每一遍都枚举每一种情况不就好了??
—————————————废话分割线——————————————
dfs的一开始先计算,当前我们剩下的牌里(剩下无论是否有顺子我们都不打顺子)直接从四带一对枚举到三带一对(因为四张有的话肯定三张更优),然后这些的轮数加上单出或双出的所有总轮数加上之前出顺子的轮数去更新答案。注意四张只能带两张或者两队,不能四带一。
然后从单顺枚举到三顺深搜回溯可能打的有点烦吧……
代码:
#include<bits/stdc++.h>
using namespace std;
#define maxn 30
#define ll long long
int n,t,num[maxn],a[maxn];
int ans;
int dai()
{
int x=0;
memset(num,0,sizeof(num));
for (int i=0;i<=14;i++) num[a[i]]++;
while (num[4])
{
num[4]--;
x++;
if (num[2]>=2) num[2]-=2;
else
if (num[1]>=2) num[1]-=2;
}//能四带二或一则尽量
while (num[3]){
num[3]--;
x++;
if (num[2]) num[2]-=1;
else
if (num[1]) num[1]-=1;
}//能三带二或一则尽量
if (a[0]&&a[1]&&num[1]>=2) x--;
return x+num[1]+num[2];
}
void dfs(int x)
{
if (x>ans) return;
int tmp=dai();
if (x+tmp<ans) ans=x+tmp;
for (int i=3;i<15;i++)
{
int j=i;
while (a[j]&&j<15)
{
a[j]--;
if (j-i>=4) dfs(x+1);
j++;
}
while (j>i) a[--j]++;//回溯
}//单顺
for (int i=3;i<15;i++)
{
int j=i;
while (a[j]>=2&&j<15)
{
a[j]-=2;
if (j-i>=2) dfs(x+1);
j++;
}
while (j>i) a[--j]+=2;//回溯
}//双顺
for (int i=3;i<15;i++)
{
int j=i;
while (a[j]>=3&&j<15)
{
a[j]-=3;
if (j-i>=1) dfs(x+1);
j++;
}
while (j>i) a[--j]+=3;//回溯
}//三顺/顺子和炸弹以及三带一接连搜
}
int main()
{
freopen("landlords.in","r",stdin);
freopen("landlords.out","w",stdout);
cin>>t>>n;
for (int o=1;o<=t;o++)
{
ans=n;
memset(a,0,sizeof(a));
for (int i=1;i<=n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
if (x==0) a[y-1]++; else
if (x==1) a[14]++; else
a[x]++;//统计去重
}
dfs(0);
printf("%d\n",ans);
}
}
一点都不花里胡哨,很简单的暴力dfs,能过基础版的这道题……但是洛谷上的数据加强版是过不了……想想也是啊,如果暴力就能解决一切,那还谈什么爱情。