*【有向图最小生成树】最小树形图[LOJ140](朱刘算法)
该比赛已结束,您无法在比赛模式下递交该题目。您可以点击“在题库中打开”以普通模式查看和递交本题。
[AdditionalFile140.zip](file://AdditionalFile140.zip?type=additional_file)
Description
【题意】这是一道模板题。
给定包含 $n$ 个结点, $m$ 条有向边的一个图。试求一棵以结点 $r$ 为根的最小树形图,并输出最小树形图每条边的权值之和,如果没有以 $r$ 为根的最小树形图,输出 -1。
【输入格式】
第一行包含三个整数 $n,m,r$,意义同题目所述。
接下来 $m$ 行,每行包含三个整数 $u,v,w$,表示图中存在一条从 $u$ 指向 $v$ 的权值为 $w$ 的有向边。
【输出格式】
如果原图中存在以 r 为根的最小树形图,就输出最小树形图每条边的权值之和,否则输出 -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
【样例解释 1】
最小树形图中包含第 2, 5, 6 三条边,总权值为 1 + 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
【样例解释 2】
最小树形图中包含第 3, 5, 6 三条边,总权值为 2 + 1 + 1 = 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
【样例解释 3】
无法构成最小树形图,故输出 -1 。
【数据范围与提示】
对于所有数据,$1 \leq u, v \leq n \leq 100, 1 \leq m \leq 10^4, 1 \leq w \leq 10^6$。
Hint
#include<bits/stdc++.h>
using namespace std;
const int N = 110;
struct edge{int x,y,w;};
vector<edge>E;
int n,m,rt,in[N],pre[N],scc[N],vis[N];
int solve()
{
int ans=0;
while(True)
{
memset(in, 0x3f, sizeof(in));
memset(pre, 0, sizeof(pre));
memset(scc, 0, sizeof(scc));
memset(vis, 0, sizeof(vis));
for(auto e:E)if(e.x!=e.y && e.w<in[e.y])in[e.y]=e.w,pre[e.y]=e.x;
for(int i=1;i<=n;++i)if(i!=rt&&pre[i]==0) return -1;
for(int i=1;i<=n;++i)if(i!=rt)ans+=in[i];
int cnt = 0;
for(int i=1,x;i<=n;++i)if(!scc[i])
{
for(x=i; x!=rt && !scc[x] && vis[x]!=i; x=pre[x]) vis[x]=i;
if(x!=rt && !scc[x])
{
for(++cnt;!scc[x];x=pre[x]) scc[x]=cnt;
}
}
if(cnt==0) return ans;
for(int i=1;i<=n;++i)if(!scc[i]) scc[i]=++cnt;
for(int i=0;i<E.size();i++)
{
E[i].w=E[i].w-in[E[i].y];
E[i].x=scc[E[i].x];E[i].y=scc[E[i].y];
}
n=cnt;
rt=scc[rt];
}
}
int main()
{
scanf("%d%d%d",&n,&m,&rt);
for(int i=1,x,y,w;i<=m;++i)
{
scanf("%d%d%d",&x,&y,&w);if(xy||yrt) continue;
E.push_back(edge{x,y,w});
}
printf("%d",solve());
return 0;
}
</p>