# WC 2008 观光计划（斯坦纳树）

## 题意

https://www.lydsy.com/JudgeOnline/problem.php?id=2595

## 思路

$dp[i][j]=\min(dp[k][j]+dp[i\setminus k][j])$

$\text{chk_min}(dp[i][k],dp[i][j]+w(j,k))$

## 代码

#include<bits/stdc++.h>
#define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i)
#define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i)
template<typename T,typename _T>inline bool chk_min(T &x,const _T y){return y<x?x=y,1:0;}
template<typename T,typename _T>inline bool chk_max(T &x,const _T y){return x<y?x=y,1:0;}
typedef long long ll;
template<const int N,const int M,typename T>struct LinkedList
{
};
struct node
{
int at,path;
bool operator <(const node &_)const{return path>_.path;}
};

std::priority_queue<node>Q;
int dp[(1<<10)+3][103];
int las[(1<<10)+3][103];
bool mark[103];
int mp[103],ori[13];
int pw[103];
int n,m,K;

inline int hs(int x,int y){return x*m+y;}

void Steiner()
{
FOR(i,0,(1<<K)-1)FOR(j,0,n-1)dp[i][j]=1e9;
FOR(i,0,K-1)dp[1<<i][ori[i]]=0;
FOR(i,1,(1<<K)-1)
{
FOR(j,0,n-1)
for(int k=(i-1)&i;k;k=(k-1)&i)
if(chk_min(dp[i][j],dp[k][j]+dp[i^k][j]-pw[j]))
{
las[i][j]=k;
}
while(!Q.empty())Q.pop();
FOR(j,0,n-1)Q.push((node){j,dp[i][j]});
while(!Q.empty())
{
node now=Q.top();Q.pop();
int u=now.at;
if(now.path>dp[i][u])continue;
EOR(k,G,u)
{
int v=G[k],w=pw[v];
if(chk_min(dp[i][v],dp[i][u]+w))
{
las[i][v]=u;
Q.push((node){v,dp[i][v]});
}
}
}
}
}

void backtrack(int i,int j)
{
mark[j]=1;
if(mp[j]!=-1&&i==(1<<mp[j]))return;
backtrack(las[i][j],j),backtrack(i^las[i][j],j);
else backtrack(i,las[i][j]);
}

int main()
{
scanf("%d%d",&n,&m);
FOR(i,0,n-1)FOR(j,0,m-1)
{
scanf("%d",&pw[hs(i,j)]);
if(!pw[hs(i,j)])mp[hs(i,j)]=K,ori[K]=hs(i,j),K++;
else mp[hs(i,j)]=-1;
}
FOR(i,0,n-1)FOR(j,0,m-2)
{
}
FOR(i,0,n-2)FOR(j,0,m-1)
{
}
n*=m;
Steiner();
int ans=1e9,id;
FOR(i,0,n-1)if(chk_min(ans,dp[(1<<K)-1][i]))id=i;
backtrack((1<<K)-1,id);
printf("%d\n",ans);
FOR(i,0,n-1)
{
if(!pw[i])putchar('x');
else putchar(mark[i]?'o':'_');
if(i%m==m-1)putchar('\n');
}
return 0;
}

posted @ 2019-08-21 08:14  Paulliant  阅读(109)  评论(1编辑  收藏