HDU - 1827 Summer Holiday(强连通分量+贪心)

来源:互联网 发布:阿里云代理服务器 编辑:程序博客网 时间:2024/05/22 07:57

题目大意:To see a World in a Grain of Sand
And a Heaven in a Wild Flower,
Hold Infinity in the palm of your hand
And Eternity in an hour.
―― William Blake

听说lcy帮大家预定了新马泰7日游,Wiskey真是高兴的夜不能寐啊,他想着得快点把这消息告诉大家,虽然他手上有所有人的联系方式,但是一个一个联系过去实在太耗时间和电话费了。他知道其他人也有一些别人的联系方式,这样他可以通知其他人,再让其他人帮忙通知一下别人。你能帮Wiskey计算出至少要通知多少人,至少得花多少电话费就能让所有人都被通知到吗?

解题思路:求出所有的强连通分量,接着缩点,然后找出所有强连通之间的关系。
找出所有入度为零的强连通分量(这些是必须要找一个人通知的),并找出这些强连通分量中价值最小的点

#include <cstdio>#include <cstring>#define max(a,b) ((a) > (b) ? (a) : (b))#define min(a,b) ((a) < (b) ? (a) : (b))#define N 1010#define M 2010struct Edge{    int to, from, next, id;}E[M];int head[N], cost[N], pre[N], lowlink[N], sccno[N], stack[N], in[N], out[N], money[N];int n, m, tot, scc_cnt, top, dfs_clock;;bool vis[N];void AddEdge(int from, int to) {    E[tot].from = from;    E[tot].to = to;    E[tot].next = head[from];    E[tot].id = tot;    head[from] = tot++; }void init() {    memset(head, -1, sizeof(head));    tot = 0;    for (int i = 1; i <= n; i++)        scanf("%d", &cost[i]);    int u, v;    for (int i = 0; i < m; i++) {        scanf("%d%d", &u, &v);        AddEdge(u, v);    }}void dfs(int u) {    pre[u] = lowlink[u] = ++dfs_clock;    stack[++top] = u;    for (int i = head[u]; i != -1; i = E[i].next) {        int v = E[i].to;        if (!pre[v]) {            dfs(v);            lowlink[u] = min(lowlink[u], lowlink[v]);        }        else if (!sccno[v]) {            lowlink[u] = min(lowlink[u], pre[v]);        }    }    int x;    if (pre[u] == lowlink[u]) {        scc_cnt++;        while (1) {            x = stack[top--];            sccno[x] = scc_cnt;            if (x == u)                break;        }    }}void solve() {    memset(pre, 0, sizeof(pre));    memset(sccno, 0, sizeof(sccno));    dfs_clock = top = scc_cnt = 0;    for (int i = 1; i <= n; i++)        if (!pre[i])            dfs(i);    for (int i = 1; i <= scc_cnt; i++)        in[i] = 1;    memset(money, 0x3f, sizeof(money));    for (int i = 1; i <= n; i++)         money[sccno[i]] = min(money[sccno[i]], cost[i]);    int u, v;    for (int i = 0; i < tot; i++) {        u = E[i].from, v = E[i].to;        if (sccno[u] != sccno[v])            in[sccno[v]] = 0;    }    int ans_man = 0, ans_cost = 0;     for (int i = 1; i <= scc_cnt; i++)        if (in[i]) {            ans_man++;            ans_cost += money[i];        }    printf("%d %d\n", ans_man, ans_cost);}int main() {    int cas = 1;    while (scanf("%d%d", &n, &m) != EOF) {        init();        solve();    }    return 0;}
0 0
原创粉丝点击