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]);
}

 

posted @ 2018-02-19 23:30  TRTTG  阅读(314)  评论(0编辑  收藏  举报