• P3943 星空


    P3943

    思维好题

    接下来, 您将看到 :

    • 差分(??!)
    • bfs
    • 状压dp

    第一波操作(差分):

    d[i] = a[i] ^ a[i-1]

    例子: 10011100 (0表示不亮, 1为亮了) 它的"差分"数组为 11010010

    吃瓜群众: 为什么要这么表示

    let's 模拟 it

    原状态 : 10011100 -> 11010010 将第四盏到第六盏搞一下 10000000 -> 11000000

    fa♂现了没有, 差分数组位置4, 7改变, 因为异或使4到6同时改变, 他们相邻两个异或值不会改变

    而3和4, 6和7中有一个值改变, 那么他们异或值也会改变

    同样的, 如果操作第四盏到第七盏, 发现差分数组位置4的1移到了位置8(汝可模拟得知)

    所以我们要求出所有的1,移动最少几次和另一个1配对

    第二波操作(bfs):

    预处理出每一个1到其他1的距离, bfs就行啦

    第三波操作(状压dp):

    设计状态S, f[S]表示消除点集S至少要操作多少次

    f[S] = min(f[S], f[S-'两个点'] + 两点相消要走多少次);

    代码:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    using namespace std;
    const int N = 40050;
    int b[70], n, m, k;
    int a[50], f[N];
    int pos[50], g[1005000];
    inline int to(int x) {
    	return 1 << x;
    }
    queue<int> q;
    int main() {
    	cin >> n >> k >> m;
    	for (int i = 1;i <= k; i++) 
    		cin >> a[i];
    	sort(a + 1,a + k + 1);
    	int cnt = 1;
    	pos[1] = a[1];
    	for (int i = 2;i <= k; i++) 
    	if (a[i] != a[i-1] + 1) {
    		pos[++cnt] = a[i-1]+1;
    		pos[++cnt] = a[i];
    	}
    	pos[++cnt] = a[k]+1;
    	for (int i = 1;i <= m; i++) cin >> b[i];
    	memset(f, 0x3f, sizeof(f));
    	f[0] = 0;
    	q.push(0);
    	while (q.size()) {
    		int x = q.front(); q.pop();
    		for (int i = 1;i <= m; i++) {
    			int y = x + b[i];
    			if (y <= n && f[y] > n) {
    				f[y] = f[x] + 1;
    				q.push(y);
    			}
    			y = x - b[i];
    			if (y > 0 && f[y] > n) {
    				f[y] = f[x] + 1;
    				q.push(y);
    			}
    		}
    	}		
    	memset(g, 0x3f, sizeof(g));
    	g[0] = 0;
    	for (int i = 1;i < 1 << cnt; i++) {
    		int tmp = 0;
    		for (int j = 1;j <= cnt; j++) 
    			if (i & to(j-1)) tmp++;
    		if (tmp & 1) continue;
    		for (int j = 1;j <= cnt; j++) 
    			if (i & to(j-1))
    			for (int k = j + 1;k <= cnt; k++) 
    				if (i & to(k-1)) 
    					g[i] = min(g[i], g[i^to(k-1)^to(j-1)] + f[pos[k]-pos[j]]);
    	}
    	cout << g[(1 << cnt) - 1] << endl;
    	return 0;
    }
    
  • 相关阅读:
    优启通(UEFI版)重装系统
    Beta阶段项目总结
    第二个阶段团队绩效管理
    第二阶段冲刺10天 第十天
    第二阶段冲刺10天 第九天
    第二阶段冲刺10天 第八天
    第二阶段冲刺10天 第七天
    第二阶段冲刺10天 第六天
    第二阶段冲刺10天 第五天
    第二阶段冲刺10天 第四天
  • 原文地址:https://www.cnblogs.com/Hs-black/p/11626105.html
Copyright © 2020-2023  润新知