欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【bzoj1937】[Shoi2004]Mst 最小生成树

程序员文章站 2022-06-29 21:48:55
...

Description

【bzoj1937】[Shoi2004]Mst 最小生成树

Input

第一行为N、M,其中 表示顶点的数目, 表示边的数目。顶点的编号为1、2、3、……、N-1、N。接下来的M行,每行三个整数Ui,Vi,Wi,表示顶点Ui与Vi之间有一条边,其权值为Wi。所有的边在输入中会且仅会出现一次。再接着N-1行,每行两个整数Xi、Yi,表示顶点Xi与Yi之间的边是T的一条边。

Output

输出最小权值

Sample Input

6 9
1 2 2
1 3 2
2 3 3
3 4 3
1 5 1
2 6 3
4 5 4
4 6 7
5 6 6
1 3
2 3
3 4
4 5
4 6

Sample Output

8

【样例说明】

边(4,6)的权由7修改为3,代价为4
边(1,2)的权由2修改为3,代价为1
边(1,5)的权由1修改为4,代价为3
所以总代价为4+1+3=8

修改方案不唯一。

HINT

 1<=n<=50,1<=m<=800,1<=wi<=1000

n-->点数..m-->边数..wi--->边权

【解析】

st->树边->非树边->ed
把每一条非树边两端的树边找出来,如果树边比非树边小,那就连起来,流量为1,费用为权值差(我是树边-非树边)

跑一遍费用流,记得是最长路,为什么呢?因为我们要修改树边的值使它为最小生成树啊!

好好看吧,我觉得我的代码挺好理解的^-^

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node
{
	int x,y,c,d,next,other;
}a[1310000];int len,last[810];
int st,ed;
void ins(int x,int y,int c,int d)
{
	int k1,k2;
	len++;k1=len;
	a[len].x=x;a[len].y=y;a[len].c=c;a[len].d=d;
	a[len].next=last[x];last[x]=len;
	
	len++;k2=len;
	a[len].x=y;a[len].y=x;a[len].c=0;a[len].d=-d;
	a[len].next=last[y];last[y]=len;
	
	a[k1].other=k2;
	a[k2].other=k1;
}
int d[810],head,tail,list[810],pre[810];
bool v[810];
int ans;
bool spfa()
{
	for(int i=1;i<=ed;i++) d[i]=-999999999;
	d[st]=0;
	memset(v,false,sizeof(v));v[st]=true;
	list[1]=st;head=1;tail=2;
	while(head!=tail)
	{
		int x=list[head];
		for(int k=last[x];k;k=a[k].next)
		{
			int y=a[k].y;
			if(a[k].c>0 && d[y]<d[x]+a[k].d)
			{
				d[y]=d[x]+a[k].d;
				pre[y]=k;
				if(v[y]==false)
				{
					v[y]=true;
					list[tail++]=y;
					if(tail==ed+1) tail=1;
				}
			}
		}
		head++;
		if(head==ed+1) head=1;
		v[x]=false;
	}
	if(d[ed]<0) return false;
	return true;
}
void get()
{
	int x=ed,k,minn=999999999;
	while(x!=st)
	{
		k=pre[x];
		minn=min(minn,a[k].c);
		x=a[k].x;
	}
	x=ed;
	while(x!=st)
	{
		k=pre[x];
		a[k].c-=minn;
		a[a[k].other].c+=minn;
		ans+=a[k].d*minn;
		x=a[k].x;
	}
}
struct bian
{
	int x,y,c,next;
}e[810];int lenn,lastt[810];
int map[51][51],num[51][51],tree[51][51];
int n,m;
struct uuu
{
	int id,a[810];
	uuu(){id=0;}
}w[810];
int f[810];
void dfs(int x,int fa)
{
	f[x]=fa;
	for(int i=1;i<=w[x].id;i++)
	{
		if(w[x].a[i]==fa) continue;
		dfs(w[x].a[i],x);
	}
	return ;
}
void build()
{
	for(int i=1;i<=m;i++)
	{
		int x=e[i].x,y=e[i].y;
		if(tree[x][y]!=-1) continue;
		dfs(y,0);
		for(;x!=y;x=f[x])
		{
			int t=map[x][f[x]]-e[i].c;
			if(t>0) ins(tree[x][f[x]],i,1,t);
		}
	}
	for(int i=1;i<=m;i++)
	{
		if(tree[e[i].x][e[i].y]!=-1) ins(st,num[e[i].x][e[i].y],1,0);
		else ins(num[e[i].x][e[i].y],ed,1,0);
	}
}
int main()
{
	int x,y,c,kk;
	scanf("%d%d",&n,&m);
	st=m+1;ed=st+1;
	memset(num,-1,sizeof(num));
	memset(tree,-1,sizeof(tree));
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&x,&y,&c);
		map[x][y]=c;map[y][x]=c;
		num[x][y]=i;num[y][x]=i;
		e[i].x=x;e[i].y=y;e[i].c=c;
	}
	for(int i=1;i<n;i++)
	{
		scanf("%d%d",&x,&y);
		tree[x][y]=tree[y][x]=num[x][y];
		w[x].id++;w[x].a[w[x].id]=y;
		w[y].id++;w[y].a[w[y].id]=x;
	}
	build();
	ans=0;
	while(spfa()==true) get();
	printf("%d\n",ans);
	return 0;
}
相关标签: bzoj