洛谷 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[15],t[15],ans,inf=0x3f3f3f3f;
int calc()
{
    int ret=0;
    memset(t,0,sizeof t);
    for(int i=0;i<=13;i++)t[a[i]]++;
    while(t[4]&&t[2]>=2)t[4]--,t[2]-=2,ret++;
    while(t[4]&&t[1]>=2)t[4]--,t[1]-=2,ret++;
    while(t[4]&&t[2])t[4]--,t[2]--,ret++;
    while(t[3]&&t[2])t[3]--,t[2]--,ret++;
    while(t[3]&&t[1])t[3]--,t[1]--,ret++;
    return ret+t[1]+t[2]+t[3]+t[4];
}
void dfs(int u)//顺子 
{
    if(u>ans)return;
    int tmp=calc();
    if(u+tmp<ans)ans=u+tmp;
    for(int i=2,j;i<=13;i++)
    {
        for(j=i;j<=13;j++)if(a[j]<3)break;
        j--;
        if(j-i+1<2)continue;
        for(int k=j;k>=i+1;k--)
        {
            for(int l=i;l<=k;l++)a[l]-=3;
            dfs(u+1);
            for(int l=i;l<=k;l++)a[l]+=3;
        }
    }
    for(int i=2,j;i<=13;i++)
    {
        for(j=i;j<=13;j++)if(a[j]<2)break;
        j--;
        if(j-i+1<3)continue;
        for(int k=j;k>=i+2;k--)
        {
            for(int l=i;l<=k;l++)a[l]-=2;
            dfs(u+1);
            for(int l=i;l<=k;l++)a[l]+=2;
        }
    }
    for(int i=2,j;i<=13;i++)
    {
        for(j=i;j<=13;j++)if(!a[j])break;
        j--;
        if(j-i+1<5)continue;
        for(int k=j;k>=i+4;k--)
        {
            for(int l=i;l<=k;l++)a[l]--;
            dfs(u+1);
            for(int l=i;l<=k;l++)a[l]++;
        }
    }
}
int main()
{
    scanf("%d%d",&T,&n);
    while(T--)
    {
        memset(a,0,sizeof a);
        for(int i=1,x,y;i<=n;i++)
        {
            scanf("%d%d",&x,&y);
            if(x==1)x=13;
            else if(x)x--;
            a[x]++;
        }
        ans=inf; dfs(0);
        printf("%d\n",ans);
    }
    return 0;
}

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

代码如下:

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

 

posted @ 2018-07-31 10:28  Zinn  阅读(184)  评论(0编辑  收藏  举报