bzoj 3900: 交换茸角
3900: 交换茸角
Description
动物园里有 n 头麋鹿。每头麋鹿有两支茸角,每支茸角有一个重量。然而,一旦某头麋鹿上
两支茸角的重量之差过大,这头麋鹿就会失去平衡摔倒。为了不然这种悲剧发生,动物园院长决
定交换某些茸角,使得任意一头麋鹿的两角重量差不超过 c。然而,交换两支茸角十分麻烦,不
仅因为茸角需要多个人来搬运,而且会给麋鹿造成痛苦。因此,你需要计算出最少交换次数,使
得任意一头麋鹿的两角重量差不超过 c。
注意,交换两支茸角只能在两头麋鹿之间进行。因为交换同一头麋鹿的两支角是没有意义的。
Input
第一行为整数 n,c。接下来 n 行,每行两个整数,分别表示一开始每头麋鹿的两角重量。
Output
一个数,即最少交换次数。如果无论如何也不能使每头麋鹿平衡,输出 -1。
Sample Input
3 0
3 3
2 5
2 5
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; }
一念起,天涯咫尺; 一念灭,咫尺天涯。