HDU 5934:Bomb(强连通缩点)

http://acm.hdu.edu.cn/showproblem.php?pid=5934

题意:有N个炸弹,每个炸弹有一个坐标,一个爆炸范围和一个爆炸花费,如果一个炸弹的爆炸范围内有另外的炸弹,那么如果该炸弹爆炸,就会引爆所有爆炸范围内的炸弹,求让所有炸弹爆炸的最小花费。

思路:重现的时候来不及做。先n^2的把每个炸弹爆炸范围内的炸弹都连一条有向边,然后再找强连通分量缩点,这样会形成多个DAG,然后对于每个DAG找一个入度为0的点,找这个入度为0的点里面耗费最小的去引爆,就可以了。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cmath>
  4 #include <cstdlib>
  5 #include <algorithm>
  6 #include <string>
  7 #include <iostream>
  8 #include <stack>
  9 #include <map>
 10 #include <queue>
 11 using namespace std;
 12 #define N 1010
 13 #define INF 0x7fffffff
 14 struct node
 15 {
 16     int u, v, nxt;
 17 }edge[2000010];
 18 struct P
 19 {
 20     long long x, y, r, c;
 21 }p[N];
 22 int belong[N], vis[N], head[N], tot, cnt, num, dfn[N], low[N], in[N], out[N];
 23 stack<int> sta;
 24 
 25 void init() {
 26     tot = cnt = num = 0;
 27     memset(dfn, 0, sizeof(dfn));
 28     memset(belong, 0, sizeof(belong));
 29     memset(vis, 0, sizeof(vis));
 30     memset(head, -1, sizeof(head));
 31     memset(in, 0, sizeof(in));
 32     memset(out, 0, sizeof(out));
 33     while(sta.size()) sta.pop();
 34 }
 35 
 36 void add(int u, int v) {
 37     edge[tot].u = u; edge[tot].v = v; edge[tot].nxt = head[u]; head[u] = tot++;
 38 }
 39 
 40 bool dis(int u, int v) {
 41     double a = sqrt(((p[u].x - p[v].x) * (p[u].x - p[v].x) + (p[u].y - p[v].y) * (p[u].y - p[v].y)) * 1.0);
 42     if(a <= p[u].r) return true;
 43     return false;
 44 }
 45 
 46 void tarjan(int u) {
 47     vis[u] = 1;
 48     sta.push(u);
 49     dfn[u] = low[u] = ++cnt;
 50     for(int i = head[u]; ~i; i = edge[i].nxt) {
 51         int v = edge[i].v;
 52         if(!dfn[v]) {
 53             tarjan(v);
 54             if(low[v] < low[u]) low[u] = low[v];
 55         } else if(vis[v]) {
 56             if(dfn[v] < low[u]) low[u] = dfn[v];
 57         }
 58     }
 59     if(dfn[u] == low[u]) {
 60         ++num;
 61         while(true) {
 62             int v = sta.top(); sta.pop();
 63             belong[v] = num; vis[v] = 0;
 64             if(v == u) break;
 65         }
 66     }
 67 }
 68 
 69 int main()
 70 {
 71     int t, cas = 1;
 72     scanf("%d", &t);
 73     while(t--) {
 74         int n;
 75         scanf("%d", &n);
 76         init();
 77         for(int i = 1; i <= n; i++) scanf("%I64d%I64d%I64d%I64d", &p[i].x, &p[i].y, &p[i].r, &p[i].c);
 78         for(int i = 1; i <= n; i++) {
 79             for(int j = 1; j <= n; j++) {
 80                 if(i == j) continue;
 81                 if(dis(i, j)) add(i, j);
 82             }
 83         }
 84         for(int i = 1; i <= n; i++) if(!dfn[i]) tarjan(i);
 85         for(int u = 1; u <= n; u++) {
 86             for(int i = head[u]; ~i; i = edge[i].nxt) {
 87                 int v = edge[i].v;
 88                 if(belong[u] != belong[v]) {
 89                     out[belong[u]]++;
 90                     in[belong[v]]++;
 91                 }
 92             }
 93         }
 94         long long ans = 0;
 95         for(int i = 1; i <= num; i++) {
 96             if(in[i] == 0) {
 97                 int mi = INF;
 98                 for(int j = 1; j <= n; j++) {
 99                     if(belong[j] == i) {
100                         if(p[j].c < mi) mi = p[j].c;
101                     }
102                 }
103                 ans += mi;
104             }
105         }
106         printf("Case #%d: %d
", cas++, ans);
107     }
108     return 0;
109 }
原文地址:https://www.cnblogs.com/fightfordream/p/6093256.html