zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    jQuery之父:每天都写点代码
    XtraTabControl 控件使用
    Linq:使用Take和Skip实现分页
    WCF教程一之WCF是什么,能做什么
    WCF发布后远程访问的域名解析问题
    C# WinForm下,隐藏主窗体,只在进程管理器中显示进程,在任务栏,状态栏都不显示窗体的方法
    在bat脚本写入中文远行后乱码
    VS2010DebugView捕捉
    Web Service 的工作原理
    String.Format 方法
  • 原文地址:https://www.cnblogs.com/Hs-black/p/11626105.html
Copyright © 2011-2022 走看看