UVa 11183 定根的最小树形图,模板题

题意:定根的最小树形图

解法:朱刘算法

#include<stdio.h>
#include<string.h>
#define MAXN 1111
#define MAXM 44000
#define INF 1000000000
struct node
{
	int u,v,w;
}e[MAXM];
int pre[MAXN],id[MAXN],vis[MAXN],in[MAXN],ans;
int n,m,root;
bool Directed_MST(int root,int nv,int ne)  //朱刘算法
{
	int i,j,u,v;
	ans=0;
	while(1)
	{
		for(i=0;i<nv;i++) in[i]=INF;
		for(i=0;i<ne;i++)    //找出每个点入边权值的最小值
		{
			u=e[i].u; v=e[i].v;
			if(e[i].w<in[v]&&u!=v)
			{
				pre[v]=u; in[v]=e[i].w;
			}
		}
		for(i=0;i<nv;i++)    //有个出了根节点的点找不到入边,则有向图中不存在最小树形图
			if(i!=root&&in[i]==INF)
				return 0;
		int cntNode=0;       //总共有的节点数,随着缩点会改变
		memset(id,0xff,sizeof(id));  //属于第几个节点
		memset(vis,0xff,sizeof(vis));//判断是否已经被归入某个节点
		in[root]=0;
		for(i=0;i<nv;i++)
		{
			ans+=in[i];     //计算最小权值和
			v=i;
			while(vis[v]!=i&&id[v]==-1&&v!=root)   //找环,将一个环上的点归入一个编号,便于缩点
			{
				vis[v]=i; v=pre[v];
			}
			if(v!=root&&id[v]==-1)      //找到环
			{
				for(u=pre[v];u!=v;u=pre[u])  //将环上的每个点归到一个节点
					id[u]=cntNode;
				id[v]=cntNode++;       //一个环代表一个节点,缩点
			}
		}
		if(cntNode==0) break;
		for(i=0;i<nv;i++)       //记录非环上的节点
			if(id[i]==-1) id[i]=cntNode++;
		for(i=0;i<ne;i++)      //缩点,假设连接边的某个节点属于某个环,则将边上记录的改点改为缩点后的点,完成缩点操作
		{
			v=e[i].v;
			e[i].u=id[e[i].u];
			e[i].v=id[e[i].v];
			if(e[i].u!=e[i].v)
				e[i].w-=in[v];
		}
		nv=cntNode;      //缩点之后,节点数只有cntNode个
		root=id[root];
	}
	return 1;
}
int main()
{
	int i,j,u,v,w,cas,T;
	scanf("%d",&T);
	for(cas=1;cas<=T;cas++)
	{
		scanf("%d%d",&n,&m);
		for(i=0;i<m;i++)
			scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
		if(Directed_MST(0,n,m)) printf("Case #%d: %d\n",cas,ans);
		else printf("Case #%d: Possums!\n",cas);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值