#12【BZOJ3003】LED BFS+状压DP

题解:

看到区间修改先想一下差分

这题用差分是为了分析问题

现在的问题就变成了

原序列全为0,要使得特定的k个点变为1,每个操作改变x,y+1

然后我们会发现

对于二元组a,b我们要修改它,实际上是在找连续的区间相连,所以实质上是最短路

为什么要差分了才能这么做呢

因为原来的区间修改可能中间涉及了有效点而变得复杂

现在每次有效操作不会影响到中间的有效点

接下来状压dp这是显然的

对于每一个状态,枚举二元组(确定其中一个值,枚举另一个值)

这是因为被确定的这个值一定是其中一个二元组

在做这个之前,还需要证明的是三元组,4元组。。。是无效的

首先奇数是不可能的

看一下四元组,一定是可以拆分成两个无关的二元组

非常的智障的是我写最短路的时候只往一边走。。 应该要往两边扩展

 

#include <bits/stdc++.h>
using namespace std;
int T,n,m,k;
int len[200],s[200];
#define rg register
#define IL inline
#define N 10100
#define N2 1100000
#define INF 1e9
#define max(a,b) (a)>(b)?(a):(b)
#define min(a,b) (a)<(b)?(a):(b)
char ss[1<<17],*A=ss,*B=ss;
inline char gc(){return A==B&&(B=(A=ss)+fread(ss,1,1<<17,stdin),A==B)?EOF:*A++;}
template<class T>void read(T&x){
    rg int f=1,c;while(c=gc(),c<48||57<c)if(c=='-')f=-1;x=c^48;
    while(c=gc(),47<c&&c<58)x=(x<<3)+(x<<1)+(c^48);x*=f;
}
bool ff[N],f[N];
queue<int> q;
int dis[200][N],dp[N2];
int main()
{
  freopen("noi.in","r",stdin);
  freopen("noi.out","w",stdout);
  std::ios::sync_with_stdio(false);
  read(T);
  for (rg int TT=1;TT<=T;TT++)
  {
    memset(ff,0,sizeof(ff));
    int kk=0; 
    read(n); read(m); read(k);
    rg int x,y;
    for (rg int i=1;i<=m;i++) 
      read(x),ff[x]^=1,ff[x+1]^=1;
    for (rg int i=1;i<=n+1;i++) 
      if (ff[i]) s[++kk]=i;
    for (rg int i=1;i<=kk;i++)
      for (rg int j=1;j<=n+10;j++)
        dis[i][j]=INF; 
    for (rg int i=1;i<=k;i++) read(len[i]);
    for (rg int i=0;i<N2;i++) dp[i]=INF;
    for (rg int i=1;i<=kk;i++)
    {
      memset(f,1,sizeof(f));
      q.push(s[i]); dis[i][s[i]]=0;
      while (!q.empty())
      {
        rg int x=q.front(); q.pop();
        for (rg int j=1;j<=k;j++)
          if (x-len[j]>0&&f[x-len[j]])
          {
            dis[i][x-len[j]]=dis[i][x]+1;
            f[x-len[j]]=0;
            q.push(x-len[j]);
          }
        for (rg int j=1;j<=k;j++)
          if (x+len[j]<=n+1&&f[x+len[j]])
          {
            dis[i][x+len[j]]=dis[i][x]+1;
            f[x+len[j]]=0;
            q.push(x+len[j]);
          }
      }
    }
  /*  for (int i=1;i<=kk;i++)
    {
      cout<<endl<<endl;
      for (int j=1;j<=n;j++)
        cout<<dis[i][j]<<" ";
    } */
    for (rg int i=1;i<=kk;i++)
      for (rg int j=1;j<i;j++)
      {
        int x=(1<<(i-1))|(1<<(j-1));
        dp[x]=dis[i][s[j]];
      }
    for (rg int i=1;i<=(1<<kk)-1;i++)
    {
      rg int x;
      for (rg int j=0;j<kk;j++) 
        if ((i>>j)&1)
        {
          x=j+1; break;
        }
      for (rg int j=0;j<kk;j++)
        if ((i>>j)&1&&j+1!=x)
        {
          y=(1<<j)|(1<<(x-1));
          dp[i]=min(dp[i],dp[y]+dp[i^y]);
        }
    }
   /* for (rg int i=1;i<=(1<<kk)-1;i++)
      for (rg int j=i;j;j=i&(j-1))
      {
        for 
        dp[i]=min(dp[i],dp[j]+dp[i^j]);
      } */
    dp[(1<<kk)-1]==INF?cout<<-1<<endl:cout<<dp[(1<<kk)-1]<<endl; 
  }
  return 0;
}

 

posted @ 2018-04-29 13:32  尹吴潇  阅读(175)  评论(0编辑  收藏  举报