最小树形图模板

朱流算法,模板里的图存储方法是结构体

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<cmath>
 6 #include<queue>
 7 #include<map>
 8 #include<cctype>
 9 #include<stack>
10 #define pn putchar('\n')
11 #define pd putchar(' ')
12 #define num ch-'0'
13 #define pb push_back
14 #define mp make_pair
15 #define fi first
16 #define se second
17 #define reint register int
18 #define fre1 freopen("1.txt","r",stdin);
19 #define fre2 freopen("2.txt","w",stdout)
20 using namespace std;
21 template <typename T>
22 void read(T &res)
23 {
24     char ch;bool flag=false;
25     while(!isdigit(ch=getchar()))(ch=='-')&&(flag=true);
26     for(res=num;isdigit(ch=getchar());res=res*10+num);
27     flag&&(res=-res);
28 }
29 template <typename T>
30 void write(T x)
31 {
32     if(x<0)putchar('-'),x=-x;
33     if(x>9)write(x/10);
34     putchar(x%10+'0');
35 }
36 typedef long long ll;
37 const int INF=0x7fffffff;
38 const int inf=0x3f3f3f3f;
39 const int mod=1000000007;
40 const int N=110;
41 const int M=10010;
42 struct node {
43     int u,v,w;
44 }e[M];
45 int n,m,r;
46 int pre[N],id[N],f[N],minn[N];
47 ///f[]:类似并查集,用于缩点
48 ///id[u]:表示u在第id[u]个环中
49 ///pre[v]:表示入度为v的最小边权对应的u
50 ///minn[v]:表示入度为v的最小边权
51 int edmonds() {
52     ll ans=0;
53     int cnt=0;
54     while(true) {
55         for(int i=1;i<=n;i++)           ///重新找缩点后的最小树形图
56             id[i]=f[i]=0,minn[i]=inf;
57         for(int i=1;i<=m;i++)
58             if(e[i].u!=e[i].v&&minn[e[i].v]>e[i].w)
59             ///不是自环,且边权小于之前选定的
60                 minn[e[i].v]=e[i].w,pre[e[i].v]=e[i].u;
61         int u=minn[r]=0;
62         for(int i=1;i<=n;i++) {
63             if(minn[i]==inf)
64             ///即该点入度为0,没连接到,不存在最小树形图
65                 return -1;
66             ans+=minn[i];
67             for(u=i;u!=r&&f[u]!=i&&!id[u];u=pre[u]) f[u]=i;
68             if(u!=r&&!id[u]) {  ///存在环,进行缩点
69                 id[u]=++cnt;
70                 for(int v=pre[u];u!=v;v=pre[v]) id[v]=cnt;
71             }
72         }
73         if(!cnt) return ans;    ///不存在环,返回答案
74         for(int i=1;i<=n;i++)
75             if(!id[i]) id[i]=++cnt;  ///i结点不在树中,给它安排一个
76         for(int i=1;i<=m;i++) {
77             int temp=minn[e[i].v];
78             if((e[i].u=id[e[i].u])^(e[i].v=id[e[i].v]))
79             ///检测是否在同一个环中
80                 e[i].w-=temp;
81                 ///u=e[i].u, v=e[i].v;
82                 ///设u',v'为收缩后的点;
83                 ///当v为收缩点时,e<u,v'>=e<u,v>-minn[v];
84                 ///当u为收缩点时,在之前e<u,v>已经累加进入ans
85                 ///由每个点的入度只为1可得,e<u',v>=0;
86         }
87         n=cnt;r=id[r];cnt=0;
88     }
89 }
90 int main()
91 {
92     read(n),read(m),read(r);
93     for(int i=1;i<=m;i++)
94         read(e[i].u),read(e[i].v),read(e[i].w);
95     write(edmonds());pn;
96     return 0;
97 }

 

posted @ 2019-06-07 16:51  wuliking  阅读(185)  评论(0编辑  收藏  举报