HDU-1827
听说lcy帮大家预定了新马泰7日游,Wiskey真是高兴的夜不能寐啊,他想着得快点把这消息告诉大家,虽然他手上有所有人的联系方式,但是一个一个联系过去实在太耗时间和电话费了。他知道其他人也有一些别人的联系方式,这样他可以通知其他人,再让其他人帮忙通知一下别人。你能帮Wiskey计算出至少要通知多少人,至少得花多少电话费就能让所有人都被通知到吗?
Input多组测试数组,以EOF结束。
第一行两个整数N和M(1<=N<=1000, 1<=M<=2000),表示人数和联系对数。
接下一行有N个整数,表示Wiskey联系第i个人的电话费用。
接着有M行,每行有两个整数X,Y,表示X能联系到Y,但是不表示Y也能联系X。
Output输出最小联系人数和最小花费。
每个CASE输出答案一行。
Sample Input
12 16 2 2 2 2 2 2 2 2 2 2 2 2 1 3 3 2 2 1 3 4 2 4 3 5 5 4 4 6 6 4 7 4 7 12 7 8 8 7 8 9 10 9 11 10
Sample Output
3 6
思路:tarjan缩点后找每个分量中最便宜的加起来,入度为0的点必买.
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define inf 0x7fffffff #define maxn 1000+10 #define maxm 2000+10 struct Edge { int next,v; }edge[maxm]; int n,m,index,top,tot,scc; int head[maxn],Stack[maxn],dfn[maxn],low[maxn],belong[maxn],cost[maxn]; int indegree[maxn], outdegree[maxn]; bool instack[maxn]; int Max(int a,int b) { return a > b? a: b; } void init() { memset(head, -1, sizeof(head)); memset(instack, false, sizeof(instack)); memset(dfn, -1, sizeof(dfn)); memset(low, 0, sizeof(low)); memset(indegree, 0, sizeof(indegree)); memset(outdegree, 0, sizeof(outdegree)); memset(belong, 0,sizeof(belong)); tot = 0; index = 0; top = 0; scc = 0; } void addedge(int u,int v) { edge[tot].next = head[u]; edge[tot].v = v; head[u] = tot ++; } void tarjan(int u) { int v; dfn[u] = low[u] = ++index; Stack[top ++] = u; instack[u] = true; for(int i = head[u];i != -1;i = edge[i].next) { v = edge[i].v; if(dfn[v] == -1) { tarjan(v); if(low[v] < low[u]) low[u] = low[v]; } else { if(instack[v] && dfn[v] < low[u]) { low[u] = dfn[v]; } } } if(dfn[u] == low[u]) { scc ++; int j; do { j = Stack[--top]; instack[j] = false; belong[j] = scc; } while(j != u); } } void solve() { for(int i = 1;i <= n;i ++) { if(dfn[i] == -1) tarjan(i); } } int main() { while(scanf("%d%d", &n, &m) != EOF) { init(); for(int i = 1;i <= n;i ++) scanf("%d", &cost[i]); while(m --) { int a, b; scanf("%d%d", &a, &b); addedge(a, b); } solve(); for(int i = 1;i <= n;i ++) { for(int j = head[i];j != -1;j = edge[j].next) { int u = i; int v = edge[j].v; if(belong[u] != belong[v]) { indegree[belong[v]] ++; } } } int ans = 0,cnt = 0; int mincost; for(int i = 1;i <= scc;i ++) { mincost = inf; if(indegree[i] == 0) { cnt ++; for(int j = 1;j <= n;j ++) { if(belong[j] == i) { mincost = min(mincost, cost[j]); } } ans += mincost; } } printf("%d %d\n",cnt,ans); } return 0; }