题意:定根的最小树形图
解法:朱刘算法
#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;
}