【NOIP2015】Day1 斗地主

这里是洛谷的传送门


【分析】
强烈建议做一下luoguP2540斗地主增强版,人不能只满足于随机数据,因为出题人往往都会出一些神奇数据来满足你被卡的愿望。

这里讲一下我看见的某位大神的思路:先用f[i][j][k][l]表示当有i个炸弹,有j个三,有k个对子,有l个单牌时最少的出牌数(不考虑顺子),用动归求出每个数值,留作后用。(其实就是预处理,逃)。然后dfs顺子(单顺子、双顺子、三顺子),分别求出出顺子次数与剩下不出顺子的和值,再取其中最小值。

两张鬼牌可以看作两张单牌进入f数组,或者作为单独的一张对牌打出(不能被当成一对带)

下面放出经过我稍加修改的代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int f[30][30][30][30],ha[5];
int c[20],shun[4]={0,5,3,2};
int T,n,ans,king;
int calc(int a,int b,int c,int d)
{
    if(king==1) return f[d][c][b][a+1];
    else if(king==2) return min(f[d][c][b][a]+1,f[d][c][b][a+2]);
    else return f[d][c][b][a];
}
void dfs(int step)
{
    if(step>ans) return;
    memset(ha,0,sizeof(ha));
    for(int i=2;i<=14;i++)
        ha[c[i]]++;
    ans=min(ans,step+calc(ha[1],ha[2],ha[3],ha[4]));
    for(int k=1;k<=3;k++)
    {
        for(int i=3;i<=14;i++)
        {
            int j;
            for(j=i;j<=14&&c[j]>=k;j++)
            {
                c[j]-=k;
                if(j-i+1>=shun[k]) dfs(step+1);
            }
            for(j--;j>=i;j--)
            c[j]+=k;
        }
    }
}
int main()
{
    freopen("landlords.in","r",stdin);
    freopen("landlords.out","w",stdout);
    cin>>T>>n;
    for(int i=0;i<=n;i++)
    for(int j=0;j<=n;j++)
    for(int k=0;k<=n;k++)
    for(int l=0;l<=n;l++)
    {
        if(i*4+j*3+k*2+l>n) continue;
        f[i][j][k][l]=i+j+k+l;
        if(i)
        {
            if(i>=1)//4->3+1
            f[i][j][k][l]=min(f[i][j][k][l],f[i-1][j+1][k][l+1]);
            if(k>=2)//四带二(对子) 
            f[i][j][k][l]=min(f[i][j][k][l],f[i-1][j][k-2][l]+1);
            if(i>=2)//两炸拆成四带二
            f[i][j][k][l]=min(f[i][j][k][l],f[i-2][j][k][l]+1);
            if(k>=1)
            f[i][j][k][l]=min(f[i][j][k][l],f[i-1][j][k-1][l]+1);
            if(l>=2)//四带二(单牌)
            f[i][j][k][l]=min(f[i][j][k][l],f[i-1][j][k][l-2]+1);
            f[i][j][k][l]=min(f[i][j][k][l],f[i-1][j][k][l]+1);

        }
        if(j)
        {
            if(j>=1)//3->2+1 
            f[i][j][k][l]=min(f[i][j][k][l],f[i][j-1][k+1][l+1]);
            if(k>=1)//
            f[i][j][k][l]=min(f[i][j][k][l],f[i][j-1][k-1][l]+1);
            if(l>=1)
            f[i][j][k][l]=min(f[i][j][k][l],f[i][j-1][k][l-1]+1);
            f[i][j][k][l]=min(f[i][j][k][l],f[i][j-1][k][l]+1);
        }
        if(k)
            f[i][j][k][l]=min(f[i][j][k][l],f[i][j][k-1][l]+1);
        if(l)
            f[i][j][k][l]=min(f[i][j][k][l],f[i][j][k][l-1]+1);
    }
    while(T--)
    {
        memset(c,0,sizeof(c));
        king=0;
        for(int i=1;i<=n;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            if(x==0) king++;
            else if(x==1) c[14]++;
            else c[x]++;
        }
        ans=0;
        for(int i=2;i<=14;i++)
            if(c[i]) ans++;
        if(king) ans++;
        dfs(0);
        printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xyc1719/article/details/81190714