zoukankan      html  css  js  c++  java
  • 【BZOJ】2595: [Wc2008]游览计划

    题意

    (n * m)的网格,如果(a_{i, j} = 0)则表示景点,否则表示这里的需要的志愿者人数。求一种安排志愿者的方案使得所有景点连通且志愿者最少。

    分析

    本题可以插头dp,然而有一个东西叫斯坦纳树,来学习学习。
    (f(i, j, s))表示((i, j))为根,连通性为(s)的最少志愿者。则有转移:

    $$ f(i, j, s) = min egin{cases} f(i, j, t) + f(i, j, s-t) - a_{i, j} & t eq varnothing, t subset s \ f(i', j', s) & (i, j)与(i', j')相邻 \ end{cases} $$

    第一个转移可以直接做,然而第二个转移不是(dag)= =,所以我们得用最短路来求出来。
    所以我们状压dp一下,然后每一个状态(s)先更新了第一种转移,然后再最短路一下。
    然后完了= =

    题解

    如分析。

    #include <bits/stdc++.h>
    using namespace std;
    const int N=10, M=N*N+5, oo=0x3f3f3f3f, dx[]={1, -1, 0, 0}, dy[]={0, 0, 1, -1};
    int n, m, a[N][N], f[N][N][1<<N], p[N][N][1<<N], go[N][N], q[M], ta, fr, tot;
    bool vis[N][N], ok[N][N];
    void init() {
    	memset(f, 0x3f, sizeof f);
    	memset(p, -1, sizeof p);
    	scanf("%d%d", &n, &m);
    	for(int i=0; i<n; ++i) {
    		for(int j=0; j<m; ++j) {
    			scanf("%d", &a[i][j]);
    			if(!a[i][j]) {
    				f[i][j][go[i][j]=1<<tot++]=0;
    			}
    		}
    	}
    }
    inline int hash(const int x, const int y, const int s) {
    	return y+x*100+s*10000;
    }
    void spfa(int s) {
    	while(fr!=ta) {
    		int h=q[fr++], y=h%100, x=h/100;
    		fr=fr==M?0:fr;
    		for(int k=0; k<4; ++k) {
    			int fx=x+dx[k], fy=y+dy[k];
    			if(fx<0 || fx>=n || fy<0 || fy>=m) {
    				continue;
    			}
    			int temp=f[x][y][s]+a[fx][fy];
    			if(f[fx][fy][s]>temp) {
    				f[fx][fy][s]=temp;
    				if(!vis[fx][fy]) {
    					vis[fx][fy]=1;
    					q[ta++]=hash(fx, fy, 0);
    					ta=ta==M?0:ta;
    				}
    				p[fx][fy][s]=hash(x, y, s);
    			}
    		}
    		vis[x][y]=0;
    	}
    	fr=ta=0;
    }
    void work() {
    	int all=1<<tot;
    	for(int s=1; s<all; ++s) {
    		for(int i=0; i<n; ++i) {
    			for(int j=0; j<m; ++j) {
    				for(int t=s&(s-1); t; t=s&(t-1)) {
    					int temp=f[i][j][t]+f[i][j][s-t]-a[i][j];
    					if(f[i][j][s]>temp) {
    						f[i][j][s]=temp;
    						p[i][j][s]=hash(i, j, t);
    					}
    				}
    				if(f[i][j][s]!=oo) {
    					vis[i][j]=1;
    					q[ta++]=hash(i, j, 0);
    				}
    			}
    		}
    		spfa(s);
    	}
    }
    void dfs(int i, int j, int s) {
    	ok[i][j]=1;
    	int h=p[i][j][s];
    	if(h<0) {
    		return;
    	}
    	int y=h%100, x=(h%10000)/100, t=h/10000;
    	dfs(x, y, t);
    	if(i==x && j==y) {
    		dfs(x, y, s-t);
    	}
    }
    void out() {
    	for(int i=0; i<n; ++i) {
    		for(int j=0; j<m; ++j) {
    			if(go[i][j]) {
    				printf("%d
    ", f[i][j][(1<<tot)-1]);
    				dfs(i, j, (1<<tot)-1);
    				return;
    			}
    		}
    	}
    }
    void prin() {
    	out();
    	for(int i=0; i<n; ++i) {
    		for(int j=0; j<m; ++j) {
    			if(go[i][j]) {
    				putchar('x');
    			}
    			else if(ok[i][j]) {
    				putchar('o');
    			}
    			else {
    				putchar('_');
    			}
    		}
    		puts("");
    	}
    }
    int main() {
    	init();
    	work();
    	prin();
    	return 0;
    }
  • 相关阅读:
    数据库编程总结
    Excel文件操作方式比较
    大数据导入Excel
    导出Excel
    duilib库分析: 消息流程分析
    ucosII移植
    Log Parser Studio 分析 IIS 日志
    google 搜索关键字技巧
    未知的反物质世界的瞎想
    Scratch 简单的小游戏 --- 碰碰球
  • 原文地址:https://www.cnblogs.com/iwtwiioi/p/4985743.html
Copyright © 2011-2022 走看看