当前位置: 代码迷 >> 综合 >> [HDU-5934] BOMB
  详细解决方案

[HDU-5934] BOMB

热度:70   发布时间:2024-01-14 21:21:57.0

一句话题意

:n个炸弹,每个炸弹有xy坐标,爆炸半径,引爆此炸弹的费用,若B炸弹在A炸弹的爆炸半径内,A炸弹爆炸后可将B炸弹引爆,问最少话费多少能将所有炸弹引爆。


题目:

There are N bombs needing exploding.

Each bomb has three attributes: exploding radius ri, position (xi,yi) and lighting-cost ci which means you need to pay ci
cost making it explode.

If a un-lighting bomb is in or on the border the exploding area of another exploding one, the un-lighting bomb also will explode.Now you know the attributes of all bombs, please use the minimum cost to explode all bombs. 

Input
First line contains an integer T, which indicates the number of test cases.

Every test case begins with an integers N, which indicates the numbers of bombs.

In the following N lines, the ith line contains four intergers xi, yi, ri and ci, indicating the coordinate of ith bomb is (xi,yi), exploding radius is ri and lighting-cost is ci.

Limits
- 1≤T≤20
- 1≤N≤1000
- ?108≤xi,yi,ri≤108
- 1≤ci≤104
Output
For every test case, you should output ‘Case #x: y’, where x indicates the case number and counts from 1 and y is the minimum cost.
Sample Input

1
5
0 0 1 5
1 1 1 6
0 1 1 7
3 0 2 10
5 0 1 4

Sample Output

Case #1: 15

分析:

暴力显然不行,可以将每个炸弹看做点,A炸弹引爆B炸弹看做一条有向边,这样就变成了一条图论的题了。
首先来考虑最简单的情况:
1 -> 2 -> 3 -> 4
5 -> 6 -> 7 -> 8
只有两条路,这样最小费用引爆所有炸弹一定是只引爆1 5两个点,其实也就是入度为0的点。
但是可能会出现一些复杂的情况,比如出现环
1 -> 2 –> 5 –> 6
↑ ↓
4 <- 3
1 2 3 4 互成一个环,那么应该怎么点呢?
我们可以把这个环看成一个点 (这个点用X表示)
那么就成了x —> 5 —> 6
那不就又成了一条线了?
现在还有一个问题,就是引爆这个X的费用是多少?
因为这个X是一个环,就光看X而言,引爆X中任意一个炸弹,都可以将X内所有炸弹引爆。所以,X的费用其实就是X在内的所有炸弹的最小的那个费用。
找出这个环就需要用到tarjan找出强连通分量缩点了
缩点之后只需要求出所有入度为0的点代表的炸弹的费用之和就是答案了。


AC代码:

#include <cstring>
#include <iostream>
#include <cstdio>
#include <climits>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <map>
#include <stack>using namespace std;const int maxn = 1010;stack <int> stk;
int timer, num, dfn[maxn], low[maxn], new_num[maxn],cost[maxn], instk[maxn];//tarjan
int head[maxn], in_degree[maxn], cnt;
struct Edge
{int to, next, from;
}eg[maxn * maxn];
struct bomb
{int x, y, cost;long long r;
}data[maxn];void tarjan(int id)
{low[id] = dfn[id] = ++timer;stk.push(id);instk[id] = true;for (int i = head[id]; ~i; i = eg[i].next){int to = eg[i].to;if (!~dfn[to]){tarjan(to);low[id] = min(low[id], low[to]);}else if (instk[to]){low[id] = min(low[id], dfn[to]);}}if (low[id] == dfn[id]){num++;int v;do{v = stk.top();stk.pop();new_num[v] = num;cost[num] = min(cost[num], data[v].cost);instk[v] = false;}while (v != id);}
}void addedge(int from, int to)
{eg[cnt].from = from;eg[cnt].to = to;eg[cnt].next = head[from];head[from] = cnt++;
};void  init()
{while (!stk.empty())stk.pop();memset(head, -1, sizeof(head));memset(in_degree, 0, sizeof(in_degree));memset(dfn, -1, sizeof(dfn));memset(low, -1, sizeof(low));memset(instk, 0, sizeof(instk));memset(cost, 0x3f, sizeof(cost));cnt = 0;num = timer = 0;
}long long Dis(int x1, int y1, int x2, int y2)
{long long x = abs(x1 - x2);long long y = abs(y1 - y2);return x * x + y * y;
}int main()
{int cases, n;scanf("%d", &cases);for (int c = 1; c <= cases; c++){init();scanf("%d", &n);for (int i = 0; i < n; i++)scanf("%d %d %lld %d", &data[i].x, &data[i].y, &data[i].r, &data[i].cost);for (int i = 0; i < n; i++){for (int j = 0; j < n; j++){if (i == j)continue;if (Dis(data[i].x, data[i].y, data[j].x, data[j].y) <= data[i].r * data[i].r)addedge(i, j);}}for (int i = 0; i < n; i++)if (!~dfn[i])tarjan(i);for (int i = 0; i < cnt; i++){Edge e = eg[i];if (new_num[e.from] != new_num[e.to])in_degree[new_num[e.to]]++;}int ans = 0;for (int i = 1; i <= num; i++){if (!in_degree[i])ans += cost[i];}printf("Case #%d: %d\n", c, ans);}return 0;
}