【NOIP 2015】 D1 T3 斗地主

【问题描述】
这里写图片描述
这里写图片描述


【输入格式】
这里写图片描述
【输出格式】
共 T 行,每行一个整数表示打光第 i 组手牌的最少次数。


这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述


【防爆零代码】
  枚举手牌组数少的时候打光的所有可能性(30分)

#include<iostream>
int x[20001],y[20001];
using namespace std;
int main()
{
    freopen("landlords.in","r",stdin);
    freopen("landlords.out","w",stdout);
    int t,n;
    cin>>t>>n;
    for(int i=1;i<=t;i++)
    {
        for(int i=1;i<=n;i++)
          cin>>x[i]>>y[i];
        if(n==1) 
          cout<<"1"<<endl;
        if(n==2)
        {
        if(x[1]==x[2]) cout<<"1"<<endl;
        else cout<<"2"<<endl;
        }
        if(n==3)
        {
            if(x[1]==x[2]&&x[1]==x[3])  cout<<"1"<<endl;
            else if(x[1]==x[2]||x[1]==x[3]||x[2]==x[3])  cout<<"2"<<endl;
            else cout<<"3"<<endl;
        }
        if(n==4)
        {
            if(x[1]==x[2]&&x[1]==x[3]&&x[1]==x[4]) cout<<"1"<<endl;
            else
            if(x[1]==x[2]&&x[2]==x[3])
             cout<<1<<endl;
            else
            if(x[1]==x[2]&&x[2]==x[4])
             cout<<1<<endl;
            else
            if(x[1]==x[3]&&x[3]==x[4])
             cout<<1<<endl;
            else
            if(x[2]==x[3]&&x[3]==x[4])
             cout<<1<<endl;
            else
            if(x[1]==x[2]&&x[3]==x[4])
             cout<<2<<endl;
            else
            if(x[1]==x[3]&&x[2]==x[4])
             cout<<2<<endl;
            else
            if(x[1]==x[4]&&x[2]==x[3])
             cout<<2<<endl;
            else
            if(x[1]==x[2])
             cout<<3<<endl;
            else
            if(x[1]==x[3])
             cout<<3<<endl;
            else
            if(x[1]==x[4])
             cout<<3<<endl;
            else
            if(x[2]==x[3])
             cout<<3<<endl;
             else
            if(x[2]==x[4])
             cout<<3<<endl;
             else
            if(x[3]==x[4])
             cout<<3<<endl;
             else
             cout<<4<<endl;
        }

    }
}

【正解】
1.花色在本题中无用
2.出牌顺序除了顺子之外对打完手牌次数无影响
3.如果不打顺子,打完手牌次数一定,所以dfs搜索出单顺子,双顺子,三顺子后的总步数,然后更新答案
4.王要单独出

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
int a[15],num[15];
int n,t,ans;
using namespace std;
int chupai()
{
    memset(num,0,sizeof(num));
    for(int i=0;i<=13;i++)
        num[a[i]]++;
    int tot=0;
    while(num[4]&&num[2]>1)
    {
        num[4]--;
        num[2]-= 2;
        tot++;
    }
    while(num[4]&&num[1]>1)
    {
        num[4]--;
        num[1]-=2;
        tot++;
    }
    while(num[4]&&num[2])
    {
        num[4]--;
        num[2]--;
        tot++;
    }
    while(num[3] && num[2])
    {
        num[3]--;
        num[2]--;
        tot++;
    }
    while(num[3]&&num[1])
    {
        num[3]--;
        num[1]--;
        tot++;
    }
    return tot+num[1]+num[2]+num[3]+num[4];
}
void dfs(int step)
{
    if(step>=ans)
    {
        return;
    }
    int temp=chupai();
    if(temp+step<ans)
      ans=temp+step;

    for(int i=2;i<=13;i++)
    {
        int j=i;
        while(a[j]>=3)
          j++;
        if(j-i>=2)
        {
            for(int j2=i+1;j2<=j-1;j2++)
            {
                for(int k=i;k<=j2;k++)
                  a[k]-=3;
                dfs(step+1);
                for(int k=i;k<=j2;k++)
                  a[k]+=3;
            }
        }
    }

    for(int i=2;i<=13;i++)
    {
        int j=i;
        while(a[j]>=2)
          j++;
        if(j-i>=3)
        {
            for(int j2=i+2;j2<=j-1;j2++)
            {
                for(int k=i;k<=j2;k++)
                  a[k]-=2;
                dfs(step+1);
                for(int k=i;k<=j2;k++)
                  a[k]+=2;
            }
        }
    }

    for(int i=2;i<=13;i++)
    {
        int j=i;
        while(a[j]>=1)
          j++;
        if(j-i>=5)
        {
            for(int j2=i+4;j2<=j-1;j2++)
            {
                for(int k=i;k<=j2;k++)
                  a[k]--;
                dfs(step+1);
                for(int k=i;k<=j2;k++)
                  a[k]++;
            }
        }
    }
}
int main()
{
    freopen("landlords.in","r",stdin);
    freopen("landlords.out","w",stdout);
    scanf("%d%d",&t,&n);
    while(t--)
    {
        memset(a,0,sizeof(a));
        for(int i=1;i<=n;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            if(x==1)//转换A 
              x=13;
            else
            {
                if(x!=0)
                  x--;
            }
                a[x]++;
        }
        ans=9999999;
        dfs(0);
        printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/shm20000412/article/details/52756224
今日推荐