您的位置:首页 > 其它

HDU 5934 Bomb (tarjan缩点)

2017-09-20 00:09 387 查看


HDU5934 Bomb(2016杭州CCPC第二题)(强连通缩点)


Bomb

Time Limit: 2000/1000 MS (Java/Others)    Memory
Limit: 65536/32768 K (Java/Others)

Total Submission(s): 26    Accepted Submission(s): 10
[align=left]Problem Description[/align]
There are N bombs
needing exploding.

Each bomb has three attributes: exploding radius ri,
position (xi,yi) and
lighting-cost ciwhich
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.
[align=left]Input[/align]
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
 
[align=left]Output[/align]
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.
 
[align=left]Sample Input[/align]

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

[align=left]Sample Output[/align]

Case #1: 15

题目大意:

给你N个炸弹,对应已知其坐标和爆炸范围,以及引爆这个炸弹需要的花费,对应如果引爆了炸弹a,没有引爆炸弹b,但是b炸弹在a炸弹的作用范围之内,那么b炸弹也会被引爆,问将所有炸弹都引爆需要的最小花费。

思路:

1、经典的最小点基的模型。我们首先O(n^2)预处理哪些炸弹可以被哪些炸弹引爆,得到一个有向图。

2、如果图中有有向环的话,我们可以将这一个有向环看成一个点,因为环内任意一个炸弹都能引爆这个环内所有的炸弹,所以我们使用Tarjan/Kosaraju之类的强连通算法缩点染色,使得图变成一个DAG(有向无环)图。

3、如果当前图变成了一个DAG图,那么度为0的节点一定是需要引爆的炸弹,因为这个节点中的炸弹不可能通过其他炸弹来引爆,只能通过直接引爆来达到引爆的目的,所以我们都将问题锁定在度为0的关键节点上来讨论,也就是所谓的最小点基问题。然后我们再简单分析一下,如果我们将所有度为0的节点都引爆了,那么度不为0的节点也一定会跟着被引爆,所以那么我们此时只需要将度为0的节点中找到一个对应的最小花费即可。

4、综上所述,我们Tarjan强联通缩点染色之后,找到度为0的节点,并且在其中找到花费最小的炸弹,累加即可。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
#include <stack>
typedef long long ll;
using namespace std;
const int maxn = 1e3 + 5;
ll x[maxn], y[maxn], r[maxn];
int n, low[maxn], dfn[maxn], id[maxn], scc_cnt, dfs_cnt, mincost[maxn], val[maxn], in[maxn];
vector<int> v[maxn];
stack<int> s;
void init()
{
memset(low, 0, sizeof(low));
memset(id, 0, sizeof(id));
memset(dfn, 0, sizeof(dfn));
memset(in, 0, sizeof(in));
memset(mincost, 0x3f3f3f3f, sizeof(mincost));
scc_cnt = dfs_cnt = 0;
for(int i = 0; i < maxn; i++)
v[i].clear();
while(!s.empty())
s.pop();
}
void tarjan(int x)
{
dfn[x] = low[x] = ++ dfs_cnt;
s.push(x);
for(int i = 0; i < v[x].size(); i++)
{
int to = v[x][i];
if(!dfn[to])
{
tarjan(to);
low[x] = min(low[x], low[to]);
}
else if(!id[to])
low[x] = min(low[x], dfn[to]);
}
if(low[x] == dfn[x])
{
scc_cnt++;
while(1)
{
int u = s.top();
s.pop();
id[u] = scc_cnt;
mincost[scc_cnt] = min(mincost[scc_cnt], val[u]);
if(x == u) break;
}
}
}
void scc()
{
for(int i = 1; i <= n; i++)
if(!dfn[i])
tarjan(i);
}
int check(int i, int j)
{
if((x[i]-x[j]) * (x[i]-x[j]) + (y[i]-y[j]) * (y[i]-y[j]) <= r[i]*r[i])
{

return 1;
}
else
return 0;
}
int main()
{
int _, ca = 1;
cin >> _;
while(_--)
{
scanf("%d", &n);
init();
for(int i = 1; i <= n; i++)
{
scanf("%lld%lld%lld%d", &x[i], &y[i], &r[i], &val[i]);
}
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
if(check(i, j) && i != j)
v[i].push_back(j);
}
}
scc();
// for(int i = 1; i <= n; i++)
// for(int j = 0; j < v[i].size(); j++)
// printf("%d %d\n", i, v[i][j]);
int ans = 0;
for(int i = 1; i <= n; i++)
{
for(int j = 0; j < v[i].size(); j++)
{
int to = v[i][j];
if(id[i] != id[to])
{
in[id[to]]++;
}
}
}
for(int i = 1; i <= scc_cnt; i++)
{
if(in[i] == 0)
ans += mincost[i];
}
printf("Case #%d: %d\n",ca++, ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: