BZOJ2595. [Wc2008]游览计划
【题意】
N*M的图中,有k个关键点,除了关键点外每个点有点权,请你用最小的费用使得景点之间联通
【分析】
这是斯坦纳树的模板题
设F[i][s]表示以i为根的子树内,选择的关键点状态为s的最小代价
外层枚举状态S
然后考虑转移:
1.由自己的其他状态转移来F[i][s]=min{F[i][t]+F[i][s^t]}
2.由其他边走过来F[i][s]=min{F[i][s],F[j][s]+e[j][i]}
第二个式子这种三角形不等式可以spfa转移一下
注意这个题是点权,在第一种转移的时候记得减去算重复的点权即可
【代码】
#include<bits/stdc++.h> using namespace std; #define mp make_pair #define fi first #define se second #define lson now<<1 #define rson now<<1|1 typedef long long ll; typedef pair<int,int> PII; const int inf=0x3f3f3f3f; const int maxn=1025; int n,m; int a[12][12],f[12][12][maxn]; int cnt,vis[12][12]; int posx,posy; struct path { int i,j,s; }pre[12][12][maxn]; int dx[4]={0,0,1,-1}; int dy[4]={1,-1,0,0}; queue <PII> q; void spfa(int st) { while(!q.empty()) { PII u=q.front(); q.pop(); vis[u.fi][u.se]=0; for(int i=0;i<4;i++) { int tox=u.fi+dx[i]; int toy=u.se+dy[i]; if(tox>n || toy>m || tox<1 || toy<1) continue; if(f[tox][toy][st]>f[u.fi][u.se][st]+a[tox][toy]) { f[tox][toy][st]=f[u.fi][u.se][st]+a[tox][toy]; pre[tox][toy][st]=(path){u.fi,u.se,st}; if(!vis[tox][toy]) { vis[tox][toy]=1; q.push(mp(tox,toy)); } } } } } void dfs(int x,int y,int st) { vis[x][y]=1; int tx=pre[x][y][st].i,ty=pre[x][y][st].j,ts=pre[x][y][st].s; if(!tx && !ty) return; dfs(tx,ty,ts); if(x==tx && y==ty) dfs(tx,ty,st-ts); } int main() { scanf("%d%d",&n,&m); memset(f,0x3f,sizeof(f)); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { scanf("%d",&a[i][j]); if(!a[i][j]) { if(!posx) posx=i,posy=j; f[i][j][1<<cnt]=0; cnt++; } } for(int s=0;s<(1<<cnt);s++) { for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { for(int st=s;st;st--) { if((st|s)!=s) continue; if(f[i][j][s]>f[i][j][st]+f[i][j][s-st]-a[i][j]) { f[i][j][s]=f[i][j][st]+f[i][j][s-st]-a[i][j]; pre[i][j][s]=(path){i,j,st}; } } if(f[i][j][s]<inf) q.push(mp(i,j)),vis[i][j]=1; } spfa(s); } printf("%d\n",f[posx][posy][(1<<cnt)-1]); memset(vis,0,sizeof(vis)); dfs(posx,posy,(1<<cnt)-1); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if(!a[i][j]) printf("x"); else { if(vis[i][j]) printf("o"); else printf("_"); } } printf("\n"); } return 0; }