最小树形图

最小树形图学习笔记

直接上代码吧

#include<bits/stdc++.h>
using namespace std;
const int maxn=109;
const int oo=1000000000;

int n,m,r;
int w[maxn][maxn];

int flag[maxn];
int pre[maxn],vis[maxn];

int Mst(){
	int ans=0;
	
	for(;;){
		for(int i=1;i<=n;++i){
			if(i==r||flag[i])continue;
			w[i][i]=oo;pre[i]=i;
			for(int j=1;j<=n;++j){
				if(flag[j])continue;
				if(w[j][i]<w[pre[i]][i])pre[i]=j;
			}
			if(pre[i]==i)return -1;
		}
		
		int beg=0;
		for(beg=1;beg<=n;++beg){
			if(beg==r||flag[beg])continue;//!!!!!!
			int x=beg,cnt=0;
			while(x!=r&&pre[x]!=beg&&cnt<=n){
				x=pre[x];++cnt;
			}
			if(x==r||cnt>n)continue;
			break;
		}
		if(beg>n){
			for(int i=1;i<=n;++i){
				if(i!=r&&!flag[i]){
					ans+=w[pre[i]][i];
				}
			}
			return ans;
		}
		
		int x=beg;
		memset(vis,0,sizeof(vis));
		for(;;){
			ans+=w[pre[x]][x];x=pre[x];vis[x]=flag[x]=1;
			if(x==beg)break;
		}
		flag[beg]=0;
		
		for(int i=1;i<=n;++i){
			if(!vis[i])continue;
			for(int j=1;j<=n;++j){
				if(vis[j])continue;
				if(w[i][j]<w[beg][j])w[beg][j]=w[i][j];
				if(w[j][i]!=oo&&w[j][i]-w[pre[i]][i]<w[j][beg]){
					w[j][beg]=w[j][i]-w[pre[i]][i];
				}
			}
		}
	}
	return ans;
}
int main(){
	scanf("%d%d%d",&n,&m,&r);
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
			w[i][j]=oo;
		}
	}
	while(m--){
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		if(x!=y){
			w[x][y]=min(w[x][y],z);
		}
	}
	printf("%d\n",Mst());
	
	return 0;
}

BZOJ 4349 最小树形图

题解:显然是所有的堡垒先都打完一遍,

然后还有需要打的堡垒就用入边权值最小的代价打

求打完一遍的权值和

建立虚点root,向1-n连边

然后再连好读入的边,跑最小树形图就可以了

#include<bits/stdc++.h>
using namespace std;

const int maxn=109;
const int oo=1000000000;

int n,m,root;
double ans=0;
double A[maxn];int B[maxn];
double w[maxn][maxn];

double minedge[maxn];

int flag[maxn];
int vis[maxn],pre[maxn];

double Mst(){
	double ret=0;
	
	for(;;){
		for(int i=1;i<=n;++i){
			if(i==root||flag[i])continue;
			w[i][i]=oo;pre[i]=i;
			for(int j=1;j<=n;++j){
				if(flag[j])continue;
				if(w[j][i]<w[pre[i]][i])pre[i]=j;
			}
		}
		
		int beg;
		for(beg=1;beg<=n;++beg){
			if(beg==root||flag[beg])continue;
			int x=beg,cnt=0;
			while(x!=root&&pre[x]!=beg&&cnt<=n){
				x=pre[x];++cnt;
			}
			if(x==root||cnt>n)continue;
			break;
		}
		
		if(beg>n){
			for(int i=1;i<=n;++i){
				if(!flag[i]&&i!=root){
					ret+=w[pre[i]][i];
				}
			}
			return ret;
		}
		
		int x=beg;
		memset(vis,0,sizeof(vis));
		for(;;){
			ret+=w[pre[x]][x];x=pre[x];vis[x]=flag[x]=1;
			if(x==beg)break;
		}
		flag[x]=0;
		
		for(int i=1;i<=n;++i){
			if(!vis[i])continue;
			for(int j=1;j<=n;++j){
				if(vis[j])continue;
				if(w[i][j]<w[x][j])w[x][j]=w[i][j];
				if(w[j][i]!=oo&&w[j][i]-w[pre[i]][i]<w[j][x])w[j][x]=w[j][i]-w[pre[i]][i];
			}
		}
	}
}

int main(){
//	freopen("fuck.in","r",stdin);
	
	scanf("%d",&n);
	root=n+1;
	for(int i=1;i<=n+1;++i){
		for(int j=1;j<=n+1;++j){
			w[i][j]=oo;
		}
	}
	for(int i=1;i<=n;++i){
		cin>>A[i]>>B[i];
		w[root][i]=A[i];
		minedge[i]=A[i];
	}
	
	scanf("%d",&m);
	while(m--){
		int x,y;double z;
		cin>>x>>y>>z;
		if(x!=y){
			w[x][y]=min(w[x][y],z);
		}
		minedge[y]=min(minedge[y],z);
	}
	n=n+1;
	ans+=Mst();
	for(int i=1;i<=n;++i)ans+=(B[i]-1)*minedge[i];
	printf("%.2f\n",ans);
	
	return 0;
}
posted @ 2018-07-09 12:03  ws_zzy  阅读(173)  评论(0编辑  收藏  举报