bzoj千题计划240:bzoj3900: 交换茸角

http://www.lydsy.com/JudgeOnline/problem.php?id=3900

 

dp[i]表示让状态为i的鹿满足要求的最少交换次数

不能枚举两头鹿交换,因为一头鹿可能交换多次后转移到下一个状态

那就枚举子集 dp[i]=min { dp[j]+dp[j^i] }

初始化:将i这个状态上的麋鹿的角从小到大排序后,若相邻的i和i+1满足 h[i+1]-h[i]<=c,则dp[i]=鹿的个数-1,否则dp[i]=inf

因为若有t只鹿,在确保一定能通过交换满足要求的情况下,直接把它需要的那个换过来即可

 

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

int a[17],b[17]; 

int dp[1<<16];

int tmp[33];

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i) scanf("%d%d",&a[i],&b[i]);
    memset(dp,63,sizeof(dp));
    int S=1<<n;
    int tot; bool tag;
    for(int i=1;i<S;++i)
    {
         tot=0;
         tag=false;
         for(int j=1;j<=n;++j)
             if(i&(1<<j-1)) 
            {
                 if(abs(a[j]-b[j])>m) tag=true;
                 tmp[++tot]=a[j],tmp[++tot]=b[j];
            }
         if(!tag) { dp[i]=0; continue; }
         sort(tmp+1,tmp+tot+1);
         for(int j=1;j<=tot;j+=2)
             if(tmp[j+1]-tmp[j]>m) { tag=false; break; }
         if(tag) dp[i]=tot/2-1;
    }
    for(int s=1;s<S;++s)
        for(int t=(s-1)&s;t;t=(t-1)&s)
            dp[s]=min(dp[s],dp[t]+dp[s^t]);
    if(dp[S-1]>=n) printf("-1");
    else printf("%d",dp[S-1]);
}

 

转载于:https://www.cnblogs.com/TheRoadToTheGold/p/8454645.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值