NOIP2015Day1T3斗地主(DFS)

  这类题...真的写不动T T

  首先可以发现没有顺子的话出牌次数是一定的, 换句话说只有顺子会影响出牌次数。

  所以可以暴搜出所有顺子的方案, 搜完之后记忆化搜索求一下a张1张同色牌, b张2张同色牌,c张3张同色牌, d张4张同色牌的最少出牌次数, 注意搜索的时候b可以拆出2个a, c可以拆出1个a, 2个b, d可以拆除2个b或者1个a, 1个c, 然后剩下的直接搜就好了, 这个效率不会估T T

  所以求可行方案用记忆化搜索也是很快的...效率大概就是状态数...

#include<iostream> 
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath> 
#include<algorithm> 
using namespace std;
const int maxn=25, inf=1e9;
int T, n, x, y;
int f[maxn][maxn][maxn][maxn], cnt[maxn], cntsum[maxn];
int least[4]={0, 5, 3, 2};
inline void read(int &k)
{
    int f=1; k=0; char c=getchar();
    while(c<'0' || c>'9') c=='-'&&(f=-1), c=getchar();
    while(c<='9' && c>='0') k=k*10+c-'0', c=getchar();
    k*=f;
}
int dfs(int a, int b, int c, int d)
{
    if(~f[a][b][c][d]) return f[a][b][c][d];
    int ans=inf;
    if(b) ans=min(ans, dfs(a+2, b-1, c, d));
    if(c) ans=min(ans, dfs(a+1, b+1, c-1, d));
    if(d) ans=min(ans, min(dfs(a+1, b, c+1, d-1), dfs(a, b+2, c, d-1)));
    if(a && c) ans=min(ans, dfs(a-1, b, c-1, d)+1);
    if(b && c) ans=min(ans, dfs(a, b-1, c-1, d)+1);
    if(a>=2 && d) ans=min(ans, dfs(a-2, b, c, d-1)+1);
    if(b>=2 && d) ans=min(ans, dfs(a, b-2, c, d-1)+1);
    return f[a][b][c][d]=min(ans, a+b+c+d); 
}
int solve(int step)
{
    int ans=inf;
    for(int i=1;i<=3;i++)
        for(int j=3;j<=14;j++)
        {
            int len=0;
            for(int k=j;k<=14;k++) if(cnt[k]>=i) len++; else break; 
            for(int k=j+least[i]-1;k<=j+len-1;k++)
            {
                for(int l=j;l<=k;l++) cnt[l]-=i;
                ans=min(ans, solve(step+1));
                for(int l=j;l<=k;l++) cnt[l]+=i;
            }
        }
    cntsum[1]=cntsum[2]=cntsum[3]=cntsum[4]=0;
    for(int i=2;i<=14;i++) cntsum[cnt[i]]++;
    if(cnt[0]==2) ans=min(ans, step+1+dfs(cntsum[1], cntsum[2], cntsum[3], cntsum[4]));
    cntsum[1]+=cnt[0];
    ans=min(ans, step+dfs(cntsum[1], cntsum[2], cntsum[3], cntsum[4]));
    return ans;
}
int main()
{
    memset(f, -1, sizeof(f)); 
    f[0][0][0][0]=0;
    read(T); read(n);
    while(T--)
    {
        memset(cnt, 0, sizeof(cnt));
        for(int i=1;i<=n;i++) read(x), read(y), cnt[x==1?14:x]++;
        printf("%d\n", solve(0));
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/Sakits/p/7795145.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值