HDU 3072
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=3072
题意:
给一个有向图,边有权值。
问最小的传递信息代价,代价是边的权值。
一个相互可达的顶点之间交换信息是不需要代价的,肯定存在一个点能把信息传递到其余所有点。
思路:
强连通分量+topo排序,强连通缩点以后找到入度为0的点进行topo,保存信息传递到每个新点用的最小代价即可。
主要是题目描述太丑难以理解。
源码:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <stack>
#include <iostream>
#include <iostream>
#include <vector>
#include <utility>
#include <queue>
using namespace std;
#define LL long long
#define inf (1000000000)
const int MAXN = 50000;
int head1[MAXN], cnt1;
int head2[MAXN], cnt2;
struct Edge
{
int u, v;
int ne, val;
Edge(){}
Edge(int _u, int _v, int _val){u = _u, v = _v, val = _val;}
}edge1[100000 * 2 + 5], edge2[100000 * 2 + 5];
void add_edge1(int u, int v, int val)
{
edge1[cnt1] = Edge(u, v, val);
edge1[cnt1].ne = head1[u];
head1[u] = cnt1++;
}
void add_edge2(int u, int v, int val)
{
edge2[cnt2] = Edge(u, v, val);
edge2[cnt2].ne = head2[u];
head2[u] = cnt2++;
}
int low[MAXN], pre[MAXN], dfs_clock;
int vis[MAXN];
int scc_cnt, sccno[MAXN];
stack<int>sta;
void tarjan_scc(int u, int p)
{
low[u] = pre[u] = ++dfs_clock;
sta.push(u);
for(int now = head1[u] ; now != -1 ; now = edge1[now].ne){
int v = edge1[now].v;
if(pre[v] == 0){
tarjan_scc(v, u);
low[u] = min(low[u], low[v]);
}
else if(!sccno[v]){
low[u] = min(low[u], pre[v]);
}
}
if(low[u] == pre[u]){
scc_cnt++;
while(!sta.empty()){
int org = sta.top(); sta.pop();
sccno[org] = scc_cnt;
if(org == u) break;
}
}
}
bool cmp2(Edge a, Edge b){return a.val < b.val;}
int in[MAXN];
int cost[MAXN];
queue<int>que;
int main()
{
int n, m;
while(scanf("%d%d", &n, &m) != EOF){
memset(head1, -1, sizeof(head1));
cnt1 = 0;
int u, v, w;
for(int i = 0 ; i < m ; i++){
scanf("%d%d%d", &u, &v, &w);
add_edge1(u, v, w);
}
memset(pre, 0, sizeof(pre));
memset(low, 0, sizeof(low));
dfs_clock = 0;
memset(sccno, 0, sizeof(sccno));
scc_cnt = 0;
while(!sta.empty()) sta.pop();
for(int i = 0 ; i < n ; i++){
if(pre[i] == 0){
tarjan_scc(i, -1);
}
}
memset(head2, -1, sizeof(head2));
cnt2 = 0;
memset(in, 0, sizeof(in));
for(int i = 0 ; i < cnt1 ; i++){
u = edge1[i].u, v = edge1[i].v;
w = edge1[i].val;
if(sccno[u] != sccno[v]){
add_edge2(sccno[u], sccno[v], w);
in[sccno[v]]++;
}
}
memset(vis, 0, sizeof(vis));
LL ans = 0;
for(int i = 1 ; i <= scc_cnt ; i++)
cost[i] = inf;
for(int i = 1 ; i <= scc_cnt ; i++){
if(in[i] == 0){
u = i;
break;
}
}
while(!que.empty()) que.pop();
que.push(u);
cost[u] = 0;
while(!que.empty()){
u = que.front(); que.pop();
for(int now = head2[u] ; now != -1 ; now = edge2[now].ne){
int v = edge2[now].v;
in[v]--;
cost[v] = min(cost[v], edge2[now].val);
if(in[v] == 0) que.push(v);
}
}
for(int i = 1 ; i <= scc_cnt ; i++)
ans += cost[i];
// sort(edge2, edge2 + cnt2, cmp2);
// for(int i = 0 ; i < cnt2 ; i++){
// u = edge2[i].u, v = edge2[i].v;
// if(vis[u] == 0 || vis[v] == 0){
// ans += edge2[i].val;
// if(vis[u] == 0) vis[u] = 1, cnt++;
// if(vis[v] == 0) vis[v] = 1, cnt++;
// }
// if(cnt == scc_cnt)
// break;
// }
printf("%I64d\n", ans);
}
return 0;
}