• BZOJ2595 [Wc2008]游览计划 【状压dp + 最短路】


    题目链接

    BZOJ2595

    题解

    著名的斯坦纳树问题

    (f[i][j][s])表示点((i,j))与景点联通状况为(s)的最小志愿者数
    (val[i][j])((i,j))需要的志愿者数

    有两种转移
    一种是自己转移

    [f[i][j][s] = min{f[i][j][e] + f[i][j][complement_s e] - val[i][j]} ]

    一种是由周围转移过来

    [f[i][j][s] = min{f[i][j][s] + f[x][y][s] + dis} ]

    第一种(O(3^{K}))枚举子集,第二种就是最短路

    纪念一下BZOJ500题,截个图,,数字挺整的

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<vector>
    #include<map>
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define mp(a,b) make_pair<int,int>(a,b)
    #define cls(s) memset(s,0,sizeof(s))
    #define cp pair<int,int>
    #define LL long long int
    using namespace std;
    const int maxn = 11,maxm = 1 << 10,INF = 1000000000;
    inline int read(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    	return out * flag;
    }
    int n,m,K,maxv;
    int f[maxn][maxn][maxm],val[maxn][maxn],id[maxn][maxn],vis[maxn][maxn];
    int head,tail,X[4] = {0,0,-1,1},Y[4] = {-1,1,0,0};
    int S[maxn][maxn];
    cp q[10000];
    struct tri{
    	int x,y,s;
    };
    vector<tri> pre[maxn][maxn][maxm];
    void spfa(int s){
    	head = 0; tail = -1;
    	REP(i,n) REP(j,m) q[++tail] = mp(i,j),vis[i][j] = true;
    	cp u; int nx,ny;
    	while (head <= tail){
    		u = q[head++];
    		vis[u.first][u.second] = false;
    		for (int k = 0; k < 4; k++){
    			nx = u.first + X[k];
    			ny = u.second + Y[k];
    			if (nx < 1 || ny < 1 || nx > n || ny > m) continue;
    			if (f[nx][ny][s] > f[u.first][u.second][s] + val[nx][ny]){
    				f[nx][ny][s] = f[u.first][u.second][s] + val[nx][ny];
    				pre[nx][ny][s].clear();
    				pre[nx][ny][s].push_back((tri){u.first,u.second,s});
    				if (!vis[nx][ny]) q[++tail] = mp(nx,ny);
    			}
    		}
    	}
    }
    void dfs(int x,int y,int s){
    	S[x][y] = true;
    	tri u;
    	for (unsigned int i = 0; i < pre[x][y][s].size(); i++){
    		u = pre[x][y][s][i];
    		dfs(u.x,u.y,u.s);
    	}
    }
    void work(){
    	maxv = (1 << K) - 1;
    	memset(f,0x3f3f3f3f,sizeof(f));
    	REP(i,n) REP(j,m){
    		f[i][j][0] = 0;
    		if (!val[i][j]) f[i][j][1 << id[i][j] - 1] = 0;
    	}
    	for (int s = 0; s <= maxv; s++){
    		REP(i,n) REP(j,m){
    			for (int e = s; e; e = (e - 1) & s){
    				if (f[i][j][s] > f[i][j][e] + f[i][j][s ^ e] - val[i][j]){
    					f[i][j][s] = f[i][j][e] + f[i][j][s ^ e] - val[i][j];
    					pre[i][j][s].clear();
    					pre[i][j][s].push_back((tri){i,j,e});
    					pre[i][j][s].push_back((tri){i,j,s ^ e});
    				}
    			}
    		}
    		spfa(s);
    	}
    	int ans = INF,x,y;
    	REP(i,n) REP(j,m) if (ans > f[i][j][maxv]) ans = f[i][j][maxv],x = i,y = j;
    	printf("%d
    ",ans);
    	dfs(x,y,maxv);
    	REP(i,n){
    		REP(j,m){
    			if (id[i][j]) putchar('x');
    			else if (S[i][j]) putchar('o');
    			else putchar('_');
    		}
    		puts("");
    	}
    }
    int main(){
    	n = read(); m = read();
    	REP(i,n) REP(j,m){
    		val[i][j] = read();
    		if (!val[i][j]) id[i][j] = ++K;
    	}
    	work();
    	return 0;
    }
    
    
  • 相关阅读:
    Boost.Asio c++ 网络编程翻译(10)
    建站手册:网站品质
    建站手册-template
    CDN:分类
    CDN:BootCDN 项目列表-摘录-20180405
    CDN:BootCDN
    CDN:目录
    CDN-template
    JavaScript-Tool:md5.js
    Regexp-Utils:基本
  • 原文地址:https://www.cnblogs.com/Mychael/p/9192253.html
Copyright © 2020-2023  润新知