hdu 5934(强连通缩点)

Bomb

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 46    Accepted Submission(s): 22


Problem Description
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
- 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 个炸弹,每个炸弹有个引爆的代价和爆炸半径,问至少花费多少代价才能引爆所有炸弹。炸弹爆炸的时候会引爆半径及内所有炸弹。


解:构造,将一个炸弹引爆另一条边的过程变成一条有向边。炸弹就是点。所以,那些入度为0的点就是必须要引爆的点(无炸弹将其引爆)。由此构图,强连通分量缩点,使得整张图无连通,求出所有入度为0的权值即可(一个强连通分量可以与一个点等价,其权值为内部最小的权值)。


代码:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<stack>
#include<algorithm>
using namespace std;
const int maxn = 1005;
const int maxm = maxn*maxn;
const int inf =999999;
struct node{
    int v,u,next;
}edge[ maxm ];
int head[ maxn ],cnt;
int vis[ maxn ],low[ maxn ],dfn[ maxn ],id;
int n,m,ans1;
int cost[ maxn ];
int belong[ maxn ],inde[ maxn ];//缩点,入度
int X[maxn],Y[maxn],R[maxn];
stack<int>q;
void init(){
    cnt=0;
    id=0;
    ans1=0;
    memset( vis,0,sizeof( vis ));
    memset( dfn,-1,sizeof(dfn) );
    memset( low,-1,sizeof( low ));
    memset( head,-1,sizeof( head ));
}
void addedge( int a,int b ){
    edge[ cnt ].v=a;
    edge[ cnt ].u=b;
    edge[ cnt ].next=head[ a ];
    head[ a ]=cnt++;
}
void tarjan( int now ){
    dfn[ now ]=low[ now ]=id++;
    vis[ now ]=1;
    q.push( now );
    for( int i=head[ now ];i!=-1;i=edge[ i ].next ){
        int next=edge[ i ].u;
        if( dfn[ next ]==-1 ){
            tarjan( next );
            low[ now ]=min( low[ now ],low[ next ]);
        }
        else if( vis[ next ]==1 ){
            low[ now ]=min( low[ now ],dfn[ next ] );
        }
    }
    if( low[ now ]==dfn[ now ] ){
        ans1++;
        while( 1 ){
            int tmp;
            tmp=q.top(),q.pop();
            vis[ tmp ]=0;
            belong[ tmp ]=ans1;
            if( tmp==now ) break;
        }
    }
}

int main(){
    int t,T=0;
    scanf("%d",&t);
    while(t--)
    {
        init();
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d%d%d",&X[i],&Y[i],&R[i],&cost[i]);
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(i==j) continue;
                long long now=1LL*(X[j]-X[i])*(X[j]-X[i])+1LL*(Y[j]-Y[i])*(Y[j]-Y[i]);
                if(now<=1LL*R[i]*R[i])
                    addedge(i,j);
            }
        }
        while( !q.empty() ) q.pop();
        for( int i=1;i<=n;i++ ){
            if( dfn[ i ]==-1 ){
                tarjan( i );
            }
        }
        int a,b;
        memset( inde,0,sizeof( inde ));
        for( int i=0;i<cnt;i++ ){
            a=edge[ i ].v,b=edge[ i ].u;
            if( belong[ a ]!=belong[ b ] ){
                inde[ belong[ b ] ]++;
            }
        }
        int ANS1,ANS2;
        ANS1=ANS2=0;
        int tmp_cnt[ maxn ];
        for( int i=1;i<=ans1;i++ ){
            if( inde[ i ]==0 )
                ANS1++;//统计缩点之后,入度为0的点
            tmp_cnt[ i ]=inf;
        }
        for( int i=1;i<=n;i++ ){
            int tmp=belong[ i ];
            if( inde[ tmp ]==0 ){
                tmp_cnt[ tmp ]=min( tmp_cnt[ tmp ],cost[ i ] );
            }
        }
        for( int i=1;i<=ans1;i++ ){
            if( tmp_cnt[ i ]!=inf )
                ANS2+=tmp_cnt[ i ];
        }
        printf("Case #%d: %d\n",++T,ANS2);
    }
    return 0;
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值