首页 > 代码库 > [HDOJ5934]Bomb(强连通分量,缩点)

[HDOJ5934]Bomb(强连通分量,缩点)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5934

题意:有n个炸弹,爆炸范围和点燃花费给你,如果一个爆炸那么它爆炸范围内的炸弹也会爆炸。问让所有炸弹爆炸的最小花费。

遍历任意两个炸弹,如果i在j的爆炸范围内,则建一条有向边。缩完点以后找入度为0的点点燃就行了。

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 
  4 typedef long long LL;
  5 typedef struct Edge {
  6     int u;
  7     int v;
  8     int next;
  9     Edge() { next = -1; }
 10 }Edge;
 11 typedef struct P {
 12     LL x, y, r;
 13     int c;
 14 }P;
 15 const int maxn = 1510;
 16 P p[maxn];
 17 
 18 int head[maxn], ecnt;
 19 Edge edge[maxn*maxn];
 20 int n, m;
 21 
 22 int bcnt, dindex;
 23 int dfn[maxn], low[maxn];
 24 int stk[maxn], top;
 25 int belong[maxn];
 26 bool instk[maxn];
 27 int ret[maxn];
 28 int in[maxn];
 29 
 30 void init() {
 31     memset(edge, 0, sizeof(edge));
 32     memset(head, -1, sizeof(head));
 33     memset(instk, 0, sizeof(instk));
 34     memset(dfn, 0, sizeof(dfn));
 35     memset(low, 0, sizeof(low));
 36     memset(belong, 0, sizeof(belong));
 37     ecnt = top = bcnt = dindex = 0;
 38 }
 39 
 40 void adde(int uu, int vv) {
 41     edge[ecnt].u = uu;
 42     edge[ecnt].v = vv;
 43     edge[ecnt].next = head[uu];
 44     head[uu] = ecnt++;
 45 }
 46 
 47 void tarjan(int u) {
 48     int v = u;
 49     dfn[u] = low[u] = ++dindex;
 50     stk[++top] = u;
 51     instk[u] = 1;
 52     for(int i = head[u]; ~i; i=edge[i].next) {
 53         v = edge[i].v;
 54         if(!dfn[v]) {
 55             tarjan(v);
 56             low[u] = min(low[u], low[v]);
 57         }
 58         else if(instk[v]) low[u] = min(low[u], dfn[v]);
 59     }
 60     if(dfn[u] == low[u]) {
 61         bcnt++;
 62         do {
 63             v = stk[top--];
 64             instk[v] = 0;
 65             belong[v] = bcnt;
 66         } while(v != u);
 67     }
 68 }
 69 
 70 LL dis(P a, P b) {
 71     LL l1 = a.x - b.x;
 72     LL l2 = a.y - b.y;
 73     return l1 * l1 + l2 * l2;
 74 }
 75 
 76 int main() {
 77     // freopen("in", "r", stdin);
 78     int T, _ = 1;
 79     scanf("%d", &T);
 80     while(T--) {
 81         scanf("%d", &n);
 82         init();
 83         memset(in, 0, sizeof(in));
 84         for(int i = 1; i <= n; i++) ret[i] = 10000000;
 85         for(int i = 1; i <= n; i++) {
 86             scanf("%I64d%I64d%I64d%d",&p[i].x,&p[i].y,&p[i].r,&p[i].c);
 87         }
 88         for(int i = 1; i <= n; i++) {
 89             for(int j = 1; j <= n; j++) {
 90                 if(i == j) continue;
 91                 LL d = dis(p[i], p[j]);
 92                 if(d <= (LL)p[i].r * p[i].r) adde(i, j);
 93             }
 94         }
 95         for(int i = 1; i <= n; i++) {
 96             if(!dfn[i]) tarjan(i);
 97         }
 98         for(int i = 0; i < ecnt; i++) {
 99             int u = edge[i].u, v = edge[i].v;
100             if(belong[u] != belong[v]) in[belong[v]]++;
101         }
102         for(int i = 1; i <= n; i++) {
103             ret[belong[i]] = min(ret[belong[i]], p[i].c);
104         }
105         int tot = 0;
106         for(int i = 1; i <= bcnt; i++) {
107             if(!in[i]) tot += ret[i];
108         }
109         printf("Case #%d: ", _++);
110         printf("%d\n", tot);
111     }
112     return 0;
113 }

 

[HDOJ5934]Bomb(强连通分量,缩点)