# [学习笔记]斯坦纳树

——by 度娘

n也不会太大

f[i][S]以i为根的树，连接了S集合关键点，的最少代价

i为根，i只是一个表示，为了转移时候连边方便

[WC2008]游览计划

#include<bits/stdc++.h>
#define il inline
#define reg register int
#define numb (ch^'0')
using namespace std;
typedef long long ll;
il void rd(int &x){
char ch;bool fl=false;
while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
for(x=numb;isdigit(ch=getchar());x=x*10+numb);
(fl==true)&&(x=-x);
}
namespace Miracle{
const int N=11;
const int P=101;
const int inf=0x3f3f3f3f;
int mv[4][2]={{+1,0},{-1,0},{0,+1},{0,-1}};
int f[N][N][1<<10];
pair<int,int>pre[N][N][1<<10];
int id[N][N];
struct po{
int x,y;
po(){}
po(int xx,int yy){
x=xx;y=yy;
}
};
queue<po>q;
int n,m,k;
int mp[N][N];
char op[N][N];
bool vis[N][N];
void spfa(int s){
while(!q.empty()){
po now=q.front();q.pop();
vis[now.x][now.y]=0;
for(reg i=0;i<4;++i){
int dx=now.x+mv[i][0],dy=now.y+mv[i][1];
if(dx<1||dx>n) continue;
if(dy<1||dy>m) continue;
if(f[dx][dy][s]>f[now.x][now.y][s]+mp[dx][dy]){
f[dx][dy][s]=f[now.x][now.y][s]+mp[dx][dy];
pre[dx][dy][s]=make_pair(now.x,now.y);
if(!vis[dx][dy]){
vis[dx][dy]=1;
q.push(po(dx,dy));
}
}
}
}
}

void check(int i,int j,int s){
if(id[i][j]==0) op[i][j]='o';
if(pre[i][j][s].first!=-1){
if(pre[i][j][s].first==0){
check(i,j,pre[i][j][s].second);
check(i,j,s^pre[i][j][s].second);
}else{
check(pre[i][j][s].first,pre[i][j][s].second,s);
}
}else return;
}
int main(){
rd(n);rd(m);
for(reg i=1;i<=n;++i){
for(reg j=1;j<=m;++j){
rd(mp[i][j]);
if(mp[i][j]==0){
++k;id[i][j]=k;
op[i][j]='x';
}

}
}
memset(f,inf,sizeof f);
for(reg i=1;i<=n;++i){
for(reg j=1;j<=m;++j){
if(mp[i][j]==0){
f[i][j][1<<(id[i][j]-1)]=0;
pre[i][j][1<<(id[i][j]-1)]=make_pair(-1,-1);
}
f[i][j][0]=0;
pre[i][j][0]=make_pair(-1,-1);
}
}
for(reg s=1;s<(1<<k);++s){
for(reg i=1;i<=n;++i){
for(reg j=1;j<=m;++j){
for(reg t=(s-1)&s;t;t=(t-1)&s){
if(f[i][j][s]>f[i][j][t]+f[i][j][s^t]-mp[i][j]){
f[i][j][s]=f[i][j][t]+f[i][j][s^t]-mp[i][j];
pre[i][j][s]=make_pair(0,t);
}
}
if(f[i][j][s]!=inf) q.push(po(i,j)),vis[i][j]=1;
}
}
spfa(s);
}
int tx,ty;
int ans=inf;
for(reg i=1;i<=n;++i){
for(reg j=1;j<=m;++j){
if(f[i][j][(1<<k)-1]<ans){
ans=f[i][j][(1<<k)-1];
tx=i;ty=j;
}
}
}
check(tx,ty,(1<<k)-1);
printf("%d\n",ans);
for(reg i=1;i<=n;++i){
for(reg j=1;j<=m;++j){
if(!op[i][j]) op[i][j]='_';
putchar(op[i][j]);
}puts("");
}
return 0;
}

}
signed main(){
Miracle::main();
return 0;
}

/*
Author: *Miracle*
Date: 2019/1/6 19:03:36
*/
View Code

Peach Blossom Spring

posted @ 2019-01-06 21:10  *Miracle*  阅读(3552)  评论(0编辑  收藏  举报