题意:给你一个n*m的矩阵,和k个点,要求使这k个点相互连接,并且使连接的代价最小(每个矩阵上都有一个权值,如果权值为0表示k个点其中的一个,连接的代价等于将这些点连接起来的路径上的权值和。)
简单的斯坦纳树,只要要要多开一个数组记录路径。如果不懂斯坦纳树,看http://endlesscount.blog.163.com/blog/static/821197872012525113427573/
#include <iostream> #include <cstdio> #include <cstring> #include <queue> #include <algorithm> using namespace std; #define INF 1061109567 const int N=205; const int M=300; int dx[]={0,1,0,-1},dy[]={1,0,-1,0}; int n,m,K; int dp[N][M],pre[N][M]; int mat[N],vis[N],st[N]; bool in[N][M]; queue<int> que; void spfa() { while(que.size()) { int top=que.front(); que.pop(); int x=top/1000/m,y=(top/1000)%m,s=top%1000; in[x*m+y][s]=0; for(int i=0;i<4;i++) { int tx=x+dx[i],ty=y+dy[i]; if(tx>=n||tx<0||ty>=m||ty<0) continue; int ts=s|st[tx*m+ty]; if(dp[tx*m+ty][ts]>dp[x*m+y][s]+mat[tx*m+ty]) { dp[tx*m+ty][ts]=dp[x*m+y][s]+mat[tx*m+ty]; pre[tx*m+ty][ts]=top; if(in[tx*m+ty][ts]==0&&s==ts) { in[tx*m+ty][ts]=1; que.push( (tx*m+ty)*1000+ts ); } } } } } void getans(int x,int y,int mask) { //cout<<x<<" "<<y<<" "<<mask<<endl; vis[x*m+y]=1; int tmp=pre[x*m+y][mask]; if(tmp==0) return; int tx=tmp/1000/m,ty=(tmp/1000)%m,s1=tmp%1000; getans(tx,ty,s1); if(tx==x&&ty==y) getans(tx,ty,((mask-s1)|st[x*m+y])); } int main() { scanf("%d%d%d",&n,&m,&K); for(int i=0;i<n;i++) for(int j=0;j<m;j++) scanf("%d",&mat[i*m+j]); memset(dp,63,sizeof(dp)); int a,b; for(int i=0;i<K;i++) { scanf("%d%d",&a,&b); a--;b--; st[a*m+b]=(1<<i); dp[a*m+b][(1<<i)]=mat[a*m+b]; } int mask=(1<<K)-1; for(int s=1;s<=mask;s++) { for(int i=0;i<n*m;i++) { if(st[i]&&!(st[i]&s)) continue; for(int p=(s-1)&s;p;p=(p-1)&s) { int s1=p|st[i],s2=(s-p)|st[i]; int d=dp[i][s1]+dp[i][s2]-mat[i]; if(d<dp[i][s]) { pre[i][s]=i*1000+s1; dp[i][s]=d; } } if(dp[i][s]!=INF) in[i][s]=1,que.push(i*1000+s); } spfa(); } printf("%d\n",dp[a*m+b][mask]); getans(a,b,mask); for(int i=0;i<n;i++,puts("")) for(int j=0;j<m;j++) { if(vis[i*m+j]) putchar('X'); else putchar('.'); } return 0; }