【BZOJ3003】差分+BFS+状压DP

orz orz orz orz BZOJ3003(权限)

3003: LED

Time Limit: 20 Sec  Memory Limit: 128 MB Submit: 159  Solved: 40 [Submit][Status][Discuss]

Description

LED屏是由一个庞大的点阵小灯泡组成的,一开始每个小灯泡都不发光。每一行一共有N个小灯泡,依次标号为1~n。现在给定K个点,要求这K个点发光,其余点必须保持熄灭状态。而这块LED屏的操作方式各种奇葩,一共有L种操作方法,第i种表示你能将任意长度恰为A_i的连续一段灯泡的状态取反(灭变亮,亮变灭)。
已知LED屏一共有m行,为了节省时间,请你算出每一行达到目标状态所需的最少操作次数。

Input

    输入文件第一行一个数m,表示LED屏的行数。
    对于LED屏的每一行:
    第一行为n,k,l,意义见上。
    第二行为k个数,表示要求发光的k个点。
    第三行为l个数,表示l种操作方式。

Output

    对于LED屏的每一行:如果无法达到目标状态,输出-1,否则输出最少次数。

Sample Input

2 10 8 2 1 2 3 5 6 7 8 9 3 5 3 2 1 1 2 3

Sample Output

2 -1 【数据规模】 对于100%的数据,T≤10,N≤10000,K≤10,L≤100,1≤A_i≤N。

HINT

Source

对于这道题首先要将原图转化-->我们将原图差分一下(这个朴素,但是十分有用的操作就是本题的关键),那么对于区间整体的异或,就可以转变为转化两点了,同样这样我们将原题恶心的区间修改这K个点,变成了每次修改两个点,然后将这2K个点消除。 由于K很小。对于从一个点作为端点出发可以修改的点和修改的最小代价,我们可以bfs一下,然后转化为状压背包就搞定了。
/*
先将数组差分,然后跑一个背包得到一个距离所需最小的,
之后bfs优化一下DP就可以了 
dp[S]将集合中的所有消掉的最小代价
 
*/
#include<stdio.h>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
int n,k,L;
const int maxn = 10005;
bool gg[maxn];
bool cf[maxn];
vector<int>ve;
int all;
int wp[maxn];
int f[maxn];
int dis[25][25];
int dp[1<<20];
queue<int>q;
void bfs(int ow) {
    memset(f,0x3f,sizeof f);
    while(q.size()) q.pop();
    q.push(ve[ow]); f[ve[ow]] = 0;
    while(q.size()) {
        int x = q.front(); q.pop();
        for(int i=1;i<=L;i++) {
            if(x+wp[i]<=n+1)
            {
                if(f[x+wp[i]]>=0x3f3f3f3f) {
                    f[x+wp[i]] = f[x] + 1;
                    q.push(x+wp[i]); 
                }
            }
            if(x-wp[i]>=1)
            {
                if(f[x-wp[i]]>=0x3f3f3f3f) {
                    f[x-wp[i]] = f[x] + 1;
                    q.push(x-wp[i]); 
                }
            }
        }
    }
    for(int i=0;i<all;i++) {
        if(i!=ow) {
            dis[ow][i] = f[ve[i]];
        }
    }
}
int logg[1<<20];
void solve() {
    memset(gg,0,sizeof gg); memset(cf,0,sizeof cf);
    ve.clear();
    all = 0;
    scanf("%d%d%d",&n,&k,&L);
    for(int i=1;i<=k;i++) {
        int x; scanf("%d",&x);
        gg[x]=1;
    }
    for(int i=1;i<=n+1;i++) {
        cf[i]=(gg[i]!=gg[i-1]);
        if(cf[i]) {
            all++; ve.push_back(i);
        }
    }
    memset(dp,0x3f,sizeof dp); dp[0]=0;
    for(int i=1;i<=L;i++) scanf("%d",&wp[i]);
    sort(wp+1,wp+1+L);
    L = unique(wp+1,wp+1+L)-wp-1;
    for(int i=0;i<all;i++) bfs(i);
    for(int i=3;i<(1<<all);i++) {
        int x = logg[i&(-i)];
        for(int y=x+1;y<all;y++) {
            if(!(i>>y)&1) continue;
            dp[i] = min(dp[i],dp[i^(1<<x)^(1<<y)]+dis[x][y]);
        }
    }
    if(dp[(1<<all)-1]<0x3f3f3f3f) printf("%d\n",dp[(1<<all)-1]);
    else printf("-1\n");
}

int main() {
    int T; scanf("%d",&T);
    for(int i=0;i<20;i++) {
        logg[(1<<i)] = i;
    }
    while(T--) solve();
}
/*
    1
    10 8 1
    1 2 3 5 6 7 8 9
    3
*/
 
posted @ 2018-10-09 20:24  Newuser233  阅读(8)  评论(0)    收藏  举报