1. 程式人生 > >BZOJ2595: [Wc2008]遊覽計劃(斯坦納樹,狀壓DP)

BZOJ2595: [Wc2008]遊覽計劃(斯坦納樹,狀壓DP)

誌願 LV out scrip esc getchar() spf else lin

Time Limit: 10 Sec Memory Limit: 256 MBSec Special Judge
Submit: 2030 Solved: 986
[Submit][Status][Discuss]

Description

技術分享圖片

技術分享圖片

Input

第一行有兩個整數,N和 M,描述方塊的數目。
接下來 N行, 每行有 M 個非負整數, 如果該整數為 0, 則該方塊為一個景點;
否則表示控制該方塊至少需要的誌願者數目。 相鄰的整數用 (若幹個) 空格隔開,
行首行末也可能有多余的空格。

Output


由 N + 1行組成。第一行為一個整數,表示你所給出的方案

中安排的誌願者總數目。
接下來 N行,每行M 個字符,描述方案中相應方塊的情況:
z ‘_’(下劃線)表示該方塊沒有安排誌願者;
z ‘o’(小寫英文字母o)表示該方塊安排了誌願者;
z ‘x’(小寫英文字母x)表示該方塊是一個景點;
註:請註意輸出格式要求,如果缺少某一行或者某一行的字符數目和要求不
一致(任何一行中,多余的空格都不允許出現) ,都可能導致該測試點不得分。

Sample Input

4 4
0 1 1 0
2 5 5 1
1 5 5 1
0 1 1 0



Sample Output

6
xoox
___o
___o
xoox

HINT

對於100%的數據,N,M,K≤10,其中K為景點的數目。輸入的所有整數均在[0,2^16]的範圍內

Source

Ljcc930提供SPJ

很明顯是斯坦納樹
$f[i][j][sta]$表示$(i,j)$這個位置,與其他景點的連通性為$sta$時的最小花費 轉移的時候一種是枚舉子集 另一種是spfa判斷, 比較套路
#include<cstdio>
#include<queue>
#include<cstring>
using
namespace std; const int limit = 1050; const int INF = 1e9; inline int read() { char c = getchar(); int x = 0, f = 1; while(c < 0 || c > 9) {if(c == -) f = -1; c = getchar();} while(c >= 0 && c <= 9) {x = x * 10 + c - 0; c = getchar();} return x * f; } #define MP(i,j) make_pair(i,j) #define se second #define fi first #define Pair pair<int,int> int N, M, tot = 0; int a[12][12], f[12][12][limit]; int xx[5] = {-1, +1, 0, 0}; int yy[5] = {0, 0, -1, +1}; int vis[12][12]; struct PRE { int x, y, S; }Pre[12][12][limit]; queue<Pair>q; void SPFA(int cur) { while(q.size() != 0) { Pair p = q.front();q.pop(); vis[p.fi][p.se] = 0; for(int i = 0; i <4; i++) { int wx = p.fi + xx[i], wy = p.se + yy[i]; if(wx < 1 || wx > N || wy < 1 || wy > M) continue; if(f[wx][wy][cur] > f[p.fi][p.se][cur] + a[wx][wy]) { f[wx][wy][cur] = f[p.fi][p.se][cur] + a[wx][wy]; Pre[wx][wy][cur] = (PRE){p.fi, p.se, cur}; if(!vis[wx][wy]) vis[wx][wy] = 1, q.push(MP(wx,wy)); } } } } void dfs(int x, int y, int now) { vis[x][y] = 1; PRE tmp = Pre[x][y][now]; 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, now - tmp.S); } int main() { N = read(); M = read(); memset(f, 0x3f, sizeof(f)); for(int i = 1; i <= N; i++) for(int j = 1; j <= M; j++) { a[i][j] = read(); if(a[i][j] == 0) f[i][j][1 << tot] = 0, tot++; } int limit = (1 << tot) - 1; for(int sta = 0; sta <= limit; sta++) { for(int i = 1; i<= N; i++) for(int j = 1; j <= M;j++) { for(int s = sta & (sta - 1); s; s = (s - 1) & sta) { if(f[i][j][s] + f[i][j][sta - s] - a[i][j] < f[i][j][sta]) f[i][j][sta] = f[i][j][s] + f[i][j][sta - s] - a[i][j], Pre[i][j][sta] = (PRE){i,j,s}; } if(f[i][j][sta] < INF) q.push(MP(i,j)), vis[i][j] = 1; } SPFA(sta); } int ansx, ansy, flag = 0; for(int i = 1; i <= N && !flag; i++) for(int j = 1; j <= M; j++) if(!a[i][j]) {ansx = i, ansy = j; flag = 1; break;} printf("%d\n",f[ansx][ansy][limit]); memset(vis, 0, sizeof(vis)); dfs(ansx, ansy, limit); for(int i = 1; i <= N; i++, puts("")) { for(int j = 1; j <= M; j++) { if(a[i][j] == 0) putchar(x); else if(vis[i][j]) putchar(o); else putchar(_); } } return 0; }

BZOJ2595: [Wc2008]遊覽計劃(斯坦納樹,狀壓DP)