HDU 5934 Bomb (tarjan缩点)

来源:互联网 发布:华美淘宝客优惠券采集 编辑:程序博客网 时间:2024/06/07 12:52


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

Problem Description
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.
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 xiyiri and ci, indicating the coordinate of ith bomb is (xi,yi), exploding radius is ri and lighting-cost is ci.

Limits
1T20
1N1000
108xi,yi,ri108
1ci104
 
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

题目大意:

给你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;}



原创粉丝点击