zoukankan      html  css  js  c++  java
  • Luogu4294 【WC2008】游览计划

    斯坦纳树(我也不知道为什么叫这个名字)是一种状压dp的套路,求在无向带花连通图中,选取边使一些特殊点连通起来的最小花费。

    具体到这题就是这样的,设(f_{u,S})表示当前根是(u),与它连通的特殊点的集合是(S)的最小花费。

    首先要合并自身的集合。

    [f_{u,S}=min_{Tsubseteq S}(f_{u,T}+f_{u,S-T}-a_u) ]

    还有换根。

    [f_{u,S}=min_{(u,v)in E}(f_{v,S}+a_u) ]

    这个东西可以用spfa来转移。

    #include<bits/stdc++.h>
    #define Rint register int
    #define MP make_pair
    #define fi first
    #define se second
    using namespace std;
    typedef pair<int, int> pii;
    const int N = 11, M = 103, d[2][4] = {{0, 1, 0, -1}, {1, 0, -1, 0}}, inf = 0x3f3f3f3f;
    int n, m, tot, a[N][N], f[N][N][1024], front, rear;
    struct Node {
    	int x, y, S;
    } pre[N][N][1024];
    pii q[M];
    bool inq[N][N];
    inline void AMOD(int &x){++ x; if(x == M) x = 0;}
    inline void spfa(int S){
    	while(front != rear){
    		pii now = q[front]; AMOD(front);
    		int ox = now.fi, oy = now.se; inq[ox][oy] = false;
    		for(Rint i = 0;i < 4;i ++){
    			int nx = ox + d[0][i], ny = oy + d[1][i];
    			if(nx >= 1 && nx <= n && ny >= 1 && ny <= m && f[nx][ny][S] > f[ox][oy][S] + a[nx][ny]){
    				f[nx][ny][S] = f[ox][oy][S] + a[nx][ny];
    				pre[nx][ny][S] = (Node){ox, oy, S};
    				if(!inq[nx][ny]){inq[nx][ny] = true; q[rear] = MP(nx, ny); AMOD(rear);}
    			}
    		}
    	}
    }
    bool vis[N][N];
    inline void dfs(int x, int y, int S){
    	vis[x][y] = true;
    	Node tmp = pre[x][y][S];
    	if(tmp.x == 0 && tmp.y == 0) return;
    	dfs(tmp.x, tmp.y, tmp.S);
    	if(tmp.x == x && tmp.y == y) dfs(tmp.x, tmp.y, S - tmp.S);
    }
    int main(){
    	scanf("%d%d", &n, &m);
    	memset(f, 0x3f, sizeof f);
    	for(Rint i = 1;i <= n;i ++)
    		for(Rint j = 1;j <= m;j ++){
    			scanf("%d", a[i] + j);
    			if(!a[i][j]) f[i][j][1 << tot] = 0, ++ tot;
    		}
    	int lim = 1 << tot;
    	for(Rint S = 0;S < lim;S ++){
    		front = rear = 0;
    		for(Rint i = 1;i <= n;i ++)
    			for(Rint j = 1;j <= m;j ++){
    				for(Rint SS = S;SS;SS = (SS - 1) & S)
    					if(f[i][j][S] > f[i][j][SS] + f[i][j][S - SS] - a[i][j]){
    						f[i][j][S] = f[i][j][SS] + f[i][j][S - SS] - a[i][j];
    						pre[i][j][S] = (Node){i, j, SS};
    					}
    				if(f[i][j][S] < inf) q[rear ++] = MP(i, j), inq[i][j] = true;
    			}
    		spfa(S);
    	}
    	int ansx = 0, ansy = 0;
    	bool flag = true;
    	for(Rint i = 1;flag && i <= n;i ++)
    		for(Rint j = 1;flag && j <= m;j ++)
    			if(!a[i][j]){ansx = i; ansy = j; flag = false;}
    	printf("%d
    ", f[ansx][ansy][lim - 1]);
    	dfs(ansx, ansy, lim - 1);
    	for(Rint i = 1;i <= n;i ++){
    		for(Rint j = 1;j <= m;j ++)
    			if(!a[i][j]) putchar('x');
    			else if(vis[i][j]) putchar('o');
    			else putchar('_');
    		putchar('
    ');
    	}
    }
    
  • 相关阅读:
    【从0开始Tornado网站】主页登录和显示的最新文章
    2014阿里巴巴网上笔试题-文章3大标题-公共最长的字符串长度
    取消改变基本数据——应用备忘录模式
    Hibernate进化史-------Hibernate概要
    xcode 快捷键
    Android多画面幻灯片:ViewPager基础上,利用与PagerTabStrip出生缺陷(源代码)
    uva 11991
    创建与删除索引
    HDU1203_I NEED A OFFER!【01背包】
    Java面试宝典2013版(超长版)
  • 原文地址:https://www.cnblogs.com/AThousandMoons/p/11720997.html
Copyright © 2011-2022 走看看