洛谷 P2668 & P2540 [ noip 2015 ] 斗地主 —— 搜索+贪心

时间:2023-03-09 08:09:42
洛谷 P2668 & P2540 [ noip 2015 ] 斗地主 —— 搜索+贪心

题目:https://www.luogu.org/problemnew/show/P2668

      https://www.luogu.org/problemnew/show/P2540

首先,如果没有顺子,那么有贪心最优解;

所以先搜索顺子,再贪心求剩余的出牌方案;

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int T,n,a[],t[],ans,inf=0x3f3f3f3f;
int calc()
{
int ret=;
memset(t,,sizeof t);
for(int i=;i<=;i++)t[a[i]]++;
while(t[]&&t[]>=)t[]--,t[]-=,ret++;
while(t[]&&t[]>=)t[]--,t[]-=,ret++;
while(t[]&&t[])t[]--,t[]--,ret++;
while(t[]&&t[])t[]--,t[]--,ret++;
while(t[]&&t[])t[]--,t[]--,ret++;
return ret+t[]+t[]+t[]+t[];
}
void dfs(int u)//顺子
{
if(u>ans)return;
int tmp=calc();
if(u+tmp<ans)ans=u+tmp;
for(int i=,j;i<=;i++)
{
for(j=i;j<=;j++)if(a[j]<)break;
j--;
if(j-i+<)continue;
for(int k=j;k>=i+;k--)
{
for(int l=i;l<=k;l++)a[l]-=;
dfs(u+);
for(int l=i;l<=k;l++)a[l]+=;
}
}
for(int i=,j;i<=;i++)
{
for(j=i;j<=;j++)if(a[j]<)break;
j--;
if(j-i+<)continue;
for(int k=j;k>=i+;k--)
{
for(int l=i;l<=k;l++)a[l]-=;
dfs(u+);
for(int l=i;l<=k;l++)a[l]+=;
}
}
for(int i=,j;i<=;i++)
{
for(j=i;j<=;j++)if(!a[j])break;
j--;
if(j-i+<)continue;
for(int k=j;k>=i+;k--)
{
for(int l=i;l<=k;l++)a[l]--;
dfs(u+);
for(int l=i;l<=k;l++)a[l]++;
}
}
}
int main()
{
scanf("%d%d",&T,&n);
while(T--)
{
memset(a,,sizeof a);
for(int i=,x,y;i<=n;i++)
{
scanf("%d%d",&x,&y);
if(x==)x=;
else if(x)x--;
a[x]++;
}
ans=inf; dfs();
printf("%d\n",ans);
}
return ;
}

增强版要考虑拆牌,看了题解,感觉好混乱...

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int T,n,a[],t[],ans,inf=0x3f3f3f3f;
int calc()
{
int ret=;bool wz=;
memset(t,,sizeof t);
if(a[]==)wz=; t[]+=a[];
for(int i=;i<=;i++)t[a[i]]++;
while(!t[]&&t[]>&&t[]==&&t[]==)t[]-=,t[]--,t[]--,ret+=;//4=3+1,出四带二单和三带二
while(!t[]&&t[]>&&t[]==&&t[]==)t[]-=,t[]--,t[]--,ret+=;//3=2+1,出四带二单和三带二
if(t[]+t[]>t[]+t[])
while(t[]&&t[]&&t[])t[]--,t[]--,t[]--,t[]++,ret++;//3=2+1,出四带二对,余一单
if(t[]+t[]>t[]+t[])
while(t[]&&t[]&&t[])t[]--,t[]--,t[]--,t[]++,ret++;//3=2+1,出四带二单,余一对
while(t[]&&t[]>)t[]--,t[]-=,ret++;
while(t[]&&t[]>)t[]--,t[]-=,ret++;
while(t[]&&t[])t[]--,t[]--,ret++;
if(t[]%==&&t[]+t[]<=)
while(t[]>)t[]-=,ret+=;//3=2+1,出三带二,三带一
while(t[]&&t[])t[]--,t[]--,ret++;
while(t[]&&t[])t[]--,t[]--,ret++;
//还剩3和4
while(t[]>&&t[])t[]-=,t[]--,ret+=;//4=2+2,出四带二和三带二
while(t[]>&&t[])t[]-=,t[]--,ret+=;//4=2+2,出2*三带二
while(t[]>)t[]-=,ret+=;//3=2+1,出三带二和三带一
while(t[]>)t[]-=,ret++;//4=2+2,出四带二对
if(wz&&t[]>=)return ret+t[]+t[]+t[]+t[]-;
else return ret+t[]+t[]+t[]+t[];
}
void dfs(int u)//顺子
{
if(u>ans)return;
int tmp=calc();
if(u+tmp<ans)ans=u+tmp;
for(int i=,j;i<=;i++)
{
for(j=i;j<=;j++)if(a[j]<)break;
j--;
if(j-i+<)continue;
for(int k=j;k>=i+;k--)
{
for(int l=i;l<=k;l++)a[l]-=;
dfs(u+);
for(int l=i;l<=k;l++)a[l]+=;
}
}
for(int i=,j;i<=;i++)
{
for(j=i;j<=;j++)if(a[j]<)break;
j--;
if(j-i+<)continue;
for(int k=j;k>=i+;k--)
{
for(int l=i;l<=k;l++)a[l]-=;
dfs(u+);
for(int l=i;l<=k;l++)a[l]+=;
}
}
for(int i=,j;i<=;i++)
{
for(j=i;j<=;j++)if(!a[j])break;
j--;
if(j-i+<)continue;
for(int k=j;k>=i+;k--)
{
for(int l=i;l<=k;l++)a[l]--;
dfs(u+);
for(int l=i;l<=k;l++)a[l]++;
}
}
}
int main()
{
scanf("%d%d",&T,&n);
while(T--)
{
memset(a,,sizeof a);
for(int i=,x,y;i<=n;i++)
{
scanf("%d%d",&x,&y);
if(x==)x=;
else if(x)x--;
a[x]++;
}
ans=inf; dfs();
printf("%d\n",ans);
}
return ;
}