zoukankan      html  css  js  c++  java
  • BZOJ2595(状压dp)

    要点

    • (f[i][j][k])经过点((i,j))且包含点集(k)的最小代价,其中k是指景点集合的枚举。
    • 考虑有两种情况:1.点((i,j))作为关键点连接了两个子集时(f[i][j][k])可以得到最小,有(f[i][j][k]=f[i][j][k_1]+f[i][j][k_2]-a[i][j], k_1|k_2=k);2.点((i,j))作为主干道发展出来的枝叶时(f[i][j][k])可以得到最小,那么它是它的邻居发展过来的,spfa跑一下即可。
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    #include <queue>
    using namespace std;
    
    const int inf = 0x3f3f3f3f;
    const int xx[] = {0, 0, -1, 1};
    const int yy[] = {1, -1, 0, 0};
    
    int N, M, K, a[11][11];
    int f[11][11][1 << 11], pre[11][11][1 << 11][3], vis[11][11];
    queue< pair<int, int> > Q;
    
    void dfs(int i, int j, int U) {
    	if (!U)	return;
    	vis[i][j] = 1;
    	int a = pre[i][j][U][0], b = pre[i][j][U][1], c = pre[i][j][U][2];
    	dfs(a, b, c);
    	if (i == a && j == b)	dfs(a, b, c ^ U);
    }
    
    void output() {
    	for (int i = 1; i <= N; i++) {
    		for (int j = 1; j <= M; j++)
    			if (!a[i][j])	putchar('x');
    			else if (vis[i][j])	putchar('o');
    			else	putchar('_');
    		puts("");
    	}
    }
    
    int main() {
    	scanf("%d %d", &N, &M);
    	for (int i = 1; i <= N; i++)
    		for (int j = 1; j <= M; j++) {
    			for (int k = 0; k < (1 << 10); k++) {
    				f[i][j][k] = inf;
    			}
    			scanf("%d", &a[i][j]);
    			if (!a[i][j]) {
    				f[i][j][1 << (K++)] = 0;
    			}
    		}
    	for (int U = 1; U < (1 << K); U++) {
    		memset(vis, 0, sizeof vis);
    		//作为枝干的转移
    		for (int i = 1; i <= N; i++)
    			for (int j = 1; j <= M; j++) {
    				for (int k = U & (U - 1); k; k = U & (k - 1)) {//枚举二进制真子集
    					int tmp = f[i][j][k] + f[i][j][k ^ U] - a[i][j];
    					if (tmp < f[i][j][U]) {
    						f[i][j][U] = tmp;
    						pre[i][j][U][0] = i;
    						pre[i][j][U][1] = j;
    						pre[i][j][U][2] = k;
    					}
    				}
    				if (f[i][j][U] < inf)	Q.push({i, j}), vis[i][j] = 1;
    			}
    		//作为树枝的转移
    		while (Q.size()) {
    			int x = Q.front().first, y = Q.front().second; Q.pop();
    			vis[x][y] = 0;
    			for (int t = 0; t < 4; t++) {
    				int nx = x + xx[t], ny = y + yy[t];
    				if (nx < 1 || nx > N || ny < 1 || ny > M)	continue;
    				if (f[nx][ny][U] > f[x][y][U] + a[nx][ny]) {
    					f[nx][ny][U] = f[x][y][U] + a[nx][ny];
    					pre[nx][ny][U][0] = x;
    					pre[nx][ny][U][1] = y;
    					pre[nx][ny][U][2] = U;
    					if (!vis[nx][ny])	Q.push({nx, ny}), vis[nx][ny] = 1;
    				}
    			}
    		}
    	}
    	for (int i = 1; i <= N; i++)
    		for (int j = 1; j <= M; j++)
    			if (!a[i][j]) {
    				memset(vis, 0, sizeof vis);
    				dfs(i, j, (1 << K) - 1);
    				printf("%d
    ", f[i][j][(1 << K) - 1]);
    				output();
    				return 0;
    			}
    }
    
  • 相关阅读:
    IGV解读
    box-cox解读
    linux命令eval的用法
    R中导入excel乱码的解决办法
    Django下实现HelloWorld
    python的list求和与求积
    win10下安装Django
    python下实现汉诺塔
    (stm32f103学习总结)—DS18B20
    (stm32f103学习总结)—GPIO结构
  • 原文地址:https://www.cnblogs.com/AlphaWA/p/10803806.html
Copyright © 2011-2022 走看看