CF 108E Garden(DP,斯坦纳树)

来源:互联网 发布:centos7安装yum 编辑:程序博客网 时间:2024/05/17 08:20

题意:给你一个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 1061109567const 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;}


原创粉丝点击