bzoj3900 交换茸角

题目链接

思路

看到n比较小,可以状压。
可以先考虑什么情况下会无法平衡。显然就是排完序之后两两相邻的不能满足小于等于c的限制。
状态。用f[i]来表示i集合中的鹿完成交换所需要的次数。
预处理。无法平衡的肯定就是INF。已经平衡的是0。其他的先暂设为k-1(k是i集合中鹿的个数)。
然后转移。每个集合可以由他的子集转移过来。即$$f[i]=min(f[i],f[j] + f[i \oplus j])$$
其中j为i的子集

代码

/*
* @Author: wxyww
* @Date:   2019-01-19 14:17:57
* @Last Modified time: 2019-01-19 14:30:13
*/
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<bitset>
using namespace std;
typedef long long ll;
const int INF = 1e9 + 7,N = 100000 + 10;
ll read() {
   ll x=0,f=1;char c=getchar();
   while(c<'0'||c>'9') {
      if(c=='-') f=-1;
      c=getchar();
   }
   while(c>='0'&&c<='9') {
      x=x*10+c-'0';
      c=getchar();
   }
   return x*f;
}
int n,c,tmp[N];
int a[20],b[20],tt[100];
int pd(int x) {
   int js = 0;
   int bz = 0;
   for(int i = 1;i <= n;++i) {
      if(1 << (i - 1) & x) {
         if(abs(a[i] - b[i]) > c) bz = 1;
         tt[++js] = a[i];
         tt[++js] = b[i];  
      } 
   }
   if(bz == 0) return 0;
   sort(tt + 1,tt + js + 1);
   for(int i = 1;i <= js;i += 2) {
      if(tt[i + 1] - tt[i] > c) return INF;
   } 
   return js / 2 - 1;
}
int f[N];
int main() {
   n = read(),c = read();
   for(int i = 1;i <= n;++i) a[i] = read(),b[i] = read();
   int K = (1 << n) - 1;
   if(pd(K) == INF) {
      puts("-1");
      return 0;
   }
   for(int i = 1;i <= K;++i) {
      f[i] = pd(i);
   }
   for(int i = 1;i <= K;++i) {
      for(int j = i;j > 0;j = (j - 1) & i) {
         f[i] = min(f[i],f[j] + f[i ^ j]);
      }
   }
   cout<<f[K];
   return 0;
}
posted @ 2019-01-24 12:42  wxyww  阅读(145)  评论(0编辑  收藏  举报