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