http://acm.hdu.edu.cn/showproblem.php?pid=3072
题意:给你n个通信点,m个传输方法,传输方法中有花费,两个点互相传输可以看做0花费,求可以传输到每个点的最小花费。
思路:将可以互通花费为0的点缩成一个点,变成DAG后就变成了求花费最小的生成树,遍历边贪心即可。这里应该复习下最小生成树算法思想,改天吧= =。这里注意题中说“kzc_tc inform one”,那就说明只能从kzc开始传递,也就是只有一个度为0的根。这样才能转化为生成树。还有从这道题我学到了无穷值在求最短路这种题中必须用0x3f3f3f3f,否则会溢出变为0而编译无效。
#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <stack>
#include <vector>
using namespace std;
typedef long long LL;
const int N = 100010;
const int INF = 0x3f3f3f3f;
stack<int>S;
int dfn[N], low[N], head[N], Belong[N], cost[N], countt, time, n, m, pos;
bool instack[N];
struct Edge
{
int from, to, next, w;
}edge[N];
void add(int u, int v, int w)
{
edge[pos].from = u;
edge[pos].to = v;
edge[pos].w = w;
edge[pos].next = head[u];
head[u] = pos++;
}
void init()
{
time = countt = pos = 0;
memset(cost, INF, sizeof(cost));
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
memset(head, -1, sizeof(head));
memset(instack, false, sizeof(instack));
}
void Tarjan(int u)
{
int v;
dfn[u] = low[u] = ++time;
instack[u] = true;
S.push(u);
for(int i = head[u]; i != -1; i = edge[i].next)
{
v = edge[i].to;
if(dfn[v] == 0)
{
Tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(instack[v] == 1)
{
low[u] = min(low[u], dfn[v]);
}
}
if(dfn[u] == low[u])
{
countt ++;
do
{
v = S.top();
S.pop();
instack[v] = false;
Belong[v] = countt;
}while(u != v);
}
}
int main()
{
// freopen("in.txt", "r", stdin);
int u, v, w;
while(~scanf("%d%d", &n, &m))
{
init();
for(int i = 1; i <= m; i++)
{
scanf("%d%d%d", &u, &v, &w);
add(u, v, w);
}
//缩点
for(int i = 0; i < n; i++)
{
if(dfn[i] == 0)
Tarjan(i);
}
for(int i = 0; i < pos; i++)//遍历每一条边,相当于生成树的思想
{
u = Belong[edge[i].from];
v = Belong[edge[i].to];
if(u != v)
{
// printf("%d ", cost[v]);
cost[v] = min(cost[v], edge[i].w);//到达该连通分量的最小花费
}
}
//遍历点
__int64 ans = 0;
for(int i = 1; i <= countt; i++)
{
if(cost[i] != INF)
{
ans += cost[i];
}
}
printf("%I64d\n", ans);
}
return 0;
}