【题意分析】
给一个有向图求最小生成树。由于是有向图所以prim和kruskal是不能解决的。这里涉及到一个求有向图最小生成树的算法叫做最小树形图。
【算法分析】
1.把这个图消去自环
2.给除了根以外的每个点找到一个最小的入边
3.如果这个最小入边集中不含有向环的话我们就可以证明这个集合就是该图的最小生成树了。
4.如果存在有向环的话,我们就将这个有向环整体看做一个顶点,同时改变图中边的权值。
5.现在假设u在该环上,这个环中指向u的边权是in[u],那么对于每条从u出发的边(u,i,w),在新图中连接(new,i,w)的边。
6.对于每条进入u的边(i,u,w),在新图中建立边(i,new,w-in[u])的边。
7.对于这个算法正确性的证明,可以参考目录下的在网络中寻找最小树形图的简易算法.pdf
1
#include <stdio.h>
2
#include <string.h>
3
using namespace std;
4
5
const unsigned int maxn=128,NOEDGE=-1;
6
unsigned int G[maxn][maxn];
7
int N,M;
8
int res;
9
unsigned int update(unsigned int o,unsigned int x)
{
10
if(o>x)return x;
11
return o;
12
}
13
bool vis[maxn];
14
void dfs(int v)
{
15
vis[v]=true;
16
for(int i=2;i<=N;++i)
17
if((!vis[i])&&G[v][i]!=NOEDGE)
18
dfs(i);
19
}
20
bool possible()
{
21
memset(vis,0,sizeof(vis));
22
dfs(1);
23
for(int i=2;i<=N;++i)
24
if(!vis[i])
25
return false;
26
return true;
27
}
28
int pre[maxn];
29
bool del[maxn];
30
void solve()
{
31
int num=N;
32
memset(del,0,sizeof(del));
33
for(;;)
{
34
int i;
35
for(i=2;i<=N;++i)
{
36
if(del[i])continue;
37
pre[i]=i;
38
G[i][i]=NOEDGE;
39
for(int j=1;j<=N;++j)
{
40
if(del[j])continue;
41
if(G[j][i]<G[pre[i]][i])
42
pre[i]=j;
43
}
44
}
45
for(i=2;i<=N;++i)
{
46
if(del[i])continue;
47
int j=i;
48
memset(vis,0,sizeof(vis));
49
while(!vis[j]&&j!=1)
{
50
vis[j]=true;
51
j=pre[j];
52
}
53
if(j==1)continue;
54
i=j;
55
res+=G[pre[i]][i];
56
for(j=pre[i];j!=i;j=pre[j])
{
57
res+=G[pre[j]][j];
58
del[j]=true;
59
}
60
for(j=1;j<=N;++j)
{
61
if(del[j])continue;
62
if(G[j][i]!=NOEDGE)
63
G[j][i]-=G[pre[i]][i];
64
}
65
for(j=pre[i];j!=i;j=pre[j])
{
66
for(int k=1;k<=N;++k)
{
67
if(del[k])continue;
68
G[i][k]=update(G[i][k],G[j][k]);
69
if(G[k][j]!=NOEDGE)
70
G[k][i]=update(G[k][i],G[k][j]-G[pre[j]][j]);
71
}
72
}
73
for(j=pre[i];j!=i;j=pre[j])
{
74
del[j]=true;
75
}
76
break;
77
}
78
if(i>N)
{
79
for(int i=2;i<=N;++i)
{
80
if(del[i])continue;
81
res+=G[pre[i]][i];
82
}
83
break;
84
}
85
}
86
}
87
int main()
{
88
for(;;)
{
89
scanf("%d%d",&N,&M);
90
if(N==0)break;
91
memset(G,NOEDGE,sizeof(G));
92
for(int i=0;i<M;++i)
{
93
unsigned int a,b,c;
94
scanf("%u%u%u",&a,&b,&c);
95
G[a][b]=c;
96
}
97
if(!possible())
{
98
puts("impossible");
99
}
100
else
{
101
res=0;
102
solve();
103
printf("%d\n",res);
104
}
105
}
106
}