题目背景
这是一道模板题。
题目描述
给定包含 n 个结点, m 条有向边的一个图。试求一棵以结点 r 为根的最小树形图,并输出最小树形图每条边的权值之和,如果没有以 r 为根的最小树形图,输出 −1。
输入格式
第一行包含三个整数 n,m,r,意义同题目所述。
接下来 m 行,每行包含三个整数 u,v,w,表示图中存在一条从 u 指向 v 的权值为 w 的有向边。
输出格式
如果原图中存在以 rrr 为根的最小树形图,就输出最小树形图每条边的权值之和,否则输出 −1。
输入输出样例
输入 #1
4 6 1
1 2 3
1 3 1
4 1 2
4 2 2
3 2 1
3 4 1
输出 #1
3
输入 #2
4 6 3
1 2 3
1 3 1
4 1 2
4 2 2
3 2 1
3 4 1
输出 #2
4
输入 #3
4 6 2
1 2 3
1 3 1
4 1 2
4 2 2
3 2 1
3 4 1
输出 #3
-1
数据范围
对于所有数据,
1
≤
u
,
v
≤
n
≤
1001
≤
u
,
v
≤
n
≤
1001
≤
u
,
v
≤
n
≤
100
,
1
≤
m
≤
1041
≤
m
≤
1
0
4
1
≤
m
≤
104
,
1
≤
w
≤
1061
≤
w
≤
1
0
6
1
≤
w
≤
106
。
1≤u,v≤n≤1001 \leq u, v \leq n \leq 1001≤u,v≤n≤100, 1≤m≤1041 \leq m \leq 10^41≤m≤104, 1≤w≤1061 \leq w \leq 10^61≤w≤106。
1≤u,v≤n≤1001≤u,v≤n≤1001≤u,v≤n≤100,1≤m≤1041≤m≤1041≤m≤104,1≤w≤1061≤w≤1061≤w≤106。
朱刘算法。积累
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define N 105
#define M 10004
using namespace std;
const int inf=1000000009;
struct node{
int u,v,w;
}edge[M];
int n,m,r,tot,ans;
inline void add(int x,int y,int z){
edge[++tot].u=x;edge[tot].v=y;edge[tot].w=z;
}
int minn[N],id[N],top[N],cnt,fa[N];
inline int get(){
while(1){
for(int i=1;i<=n;++i)id[i]=top[i]=0,minn[i]=inf;
for(int i=1;i<=m;++i){
if(edge[i].u!=edge[i].v&&edge[i].w<minn[edge[i].v]){
minn[edge[i].v]=edge[i].w;fa[edge[i].v]=edge[i].u;
}
}
int u=minn[r]=0;
for(int i=1;i<=n;++i){
if(minn[i]==inf)return 0;
ans+=minn[i];
for(u=i;u!=r&&top[u]!=i&&!id[u];u=fa[u])top[u]=i;
if(u!=r&&!id[u]){
id[u]=++cnt;
for(int v=fa[u];v!=u;v=fa[v])id[v]=cnt;
}
}
if(!cnt)return 1;
for(int i=1;i<=n;++i)if(!id[i])id[i]=++cnt;
for(int i=1;i<=m;++i){
int las=minn[edge[i].v];
if((edge[i].u=id[edge[i].u])!=(edge[i].v=id[edge[i].v]))edge[i].w-=las;
}
n=cnt;r=id[r];cnt=0;
}
}
int main(){
cin>>n>>m>>r;
for(int i=1;i<=m;++i){
cin>>edge[i].u>>edge[i].v>>edge[i].w;
}
if(get())cout<<ans<<endl;
else cout<<"-1"<<endl;
return 0;
}
/*
4 6 1
1 2 3
1 3 1
4 1 2
4 2 2
3 2 1
3 4 1
*/