朱流算法,模板里的图存储方法是结构体
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(' ') 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 }