bzoj 3900: 交换茸角

3900: 交换茸角

Description

动物园里有 n 头麋鹿。每头麋鹿有两支茸角,每支茸角有一个重量。然而,一旦某头麋鹿上
两支茸角的重量之差过大,这头麋鹿就会失去平衡摔倒。为了不然这种悲剧发生,动物园院长决
定交换某些茸角,使得任意一头麋鹿的两角重量差不超过 c。然而,交换两支茸角十分麻烦,不
仅因为茸角需要多个人来搬运,而且会给麋鹿造成痛苦。因此,你需要计算出最少交换次数,使
得任意一头麋鹿的两角重量差不超过 c。
注意,交换两支茸角只能在两头麋鹿之间进行。因为交换同一头麋鹿的两支角是没有意义的。

Input

第一行为整数 n,c。接下来 n 行,每行两个整数,分别表示一开始每头麋鹿的两角重量。

Output

一个数,即最少交换次数。如果无论如何也不能使每头麋鹿平衡,输出 -1。

Sample Input

3 0
3 3
2 5
2 5

Sample Output

1

HINT

对于 100% 的数据,n <= 16, c <= 1000000, 每支茸角重量不超过 1000000。

网上都没人写题解,还是自己写一发吧。。。

怎么说呢,n<=16是一个突破口,我们肯定要往状压上想。。

刚开始我是直接枚举状态中哪两个互相交换,但最后发现有反例,比如:

3 1

1 3

2 4

3 5

一头鹿可以进行好几次交换。。

然后改变思路,发现这题和某次的topcoder的juice有点像,先预处理出i状态下让每一头鹿进行交换的最小交换次数,如果可行的话,那么答案就是鹿的个数减1(好好想想),接下来就很简单了。。

 

#include<stdio.h>
#include<iostream>
#include<stdlib.h>
#include<algorithm>
using namespace std;
int n,m,i,j,k,p,c[40],a[20],b[20],f[(1<<16)+5];
int main()
{
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)
        scanf("%d%d",&a[i],&b[i]);
    for(i=1;i<(1<<n);i++)
    {
        k=0;p=0;
        for(j=0;(1<<j)<=i;j++)
            if(1<<j&i)
        {
            if(abs(a[j+1]-b[j+1])>m) p=1;
            k++;
            c[k]=a[j+1];
            k++;
            c[k]=b[j+1];
        }
        if(p==0) f[i]=0;else
        {
            sort(c+1,c+k+1);
            p=0;
            for(j=1;j<=k;j+=2)
            if(c[j+1]-c[j]>m) {p=1;break;}
            if(p==1) f[i]=1e9;else f[i]=k/2-1;
        }
    }
    for(i=1;i<(1<<n);i++)
     for(j=(i-1)&i;j>0;j=(j-1)&i)
     f[i]=min(f[i],f[j]+f[i^j]);
    if(f[(1<<n)-1]==1e9) cout<<"-1";else cout<<f[(1<<n)-1];
    return 0;
}

 

  

 

 

 

posted @ 2016-07-08 18:54  lwq12138  阅读(623)  评论(0编辑  收藏  举报