HDU - 5934 - Bomb (强连通缩点)

Bomb

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


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
 

Source
 


题意:有n个炸弹,每个炸弹有对应的位置(x,y),爆炸半径,点燃炸弹花费,求将全部炸弹点燃所需最小花费


思路:建图,强连通缩点,找出所有入度为0的点,它们的点燃花费之和就是答案

Tarjan

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <vector>
#include <stack>
using namespace std;
typedef long long LL;
const int N = 1e3 + 10;
int T,n,cas,ans;
int dfn[N],low[N],vis[N],dfs_num;
int indeg[N];
vector<int>G[N];
stack<int>st;
struct node{
    LL x, y, r;  // 记录坐标半径
    int cost, id; // 花费,所属强连通
}p[N];
void init(){
    dfs_num = ans = 0;
    memset(dfn, 0, sizeof dfn);
    memset(indeg, 0, sizeof indeg);
}
void tarjan(int now){
    dfn[now] = low[now] = ++dfs_num;
    st.push(now); vis[now] = 1;
    for(int i=0;i<G[now].size();i++){
        int nt = G[now][i];
        if(dfn[nt]&&!vis[nt]) continue; //在其他强连通分量中
        if(!dfn[nt]){ // 未被访问过
            tarjan(nt);
            if(low[nt]<low[now]) low[now] = low[nt];
        }else if(vis[nt]){ // 被访问过且nt可到达now
            if(dfn[nt]<low[now]) low[now] = dfn[nt];
        }
    }
    if(dfn[now]==low[now]){
        int mi = p[now].cost;
        while(!st.empty()){
            int tem = st.top(); st.pop();
            vis[tem] = 0; p[tem].id = now;
            mi = min(mi, p[tem].cost);
            if(tem==now) break;
        }
        p[now].cost = mi;
    }
}
void slove(){
    init();
    for(int i=1;i<=n;i++){
        if(dfn[i]) continue;
        tarjan(i);
    }
    for(int i=1;i<=n;i++){
        for(int j=0;j<G[i].size();j++){
            int nt = p[G[i][j]].id;
            if(nt==p[i].id) continue; // 自连边不算入度
            indeg[nt] ++;
        }
    }
    for(int i=1;i<=n;i++){
        if(p[i].id==i&&indeg[i]==0) {
            ans += p[i].cost;
        }
    }
}
int main()
{
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            G[i].clear();
            scanf("%lld%lld%lld%d",&p[i].x,&p[i].y,&p[i].r,&p[i].cost);
        }
        //建图
        for(int i=1;i<n;i++){
            for(int j=i+1;j<=n;j++){
                LL dx = p[i].x - p[j].x;
                LL dy = p[i].y - p[j].y;
                LL dis = dx*dx+dy*dy;
                if(dis<=p[i].r*p[i].r) G[i].push_back(j); // i可以炸到j
                if(dis<=p[j].r*p[j].r) G[j].push_back(i); // j可以炸到i
            }
        }
        slove();
        printf("Case #%d: %d\n",++cas,ans);
    }
    return 0;
}

Korasaju

#include<iostream>
#include<string.h>
#include<stdio.h>
#include<vector>
#include<math.h>
using namespace std;
const int maxn = 1000+10;
int T,n,c[maxn],vis[maxn],k,Index[maxn],cas = 0,ans;
double x[maxn],y[maxn],r[maxn];
vector<int>G[maxn];
vector<int>rG[maxn];
vector<int>load;
struct node {int ru,cost;}point[maxn];
void init()
{
    for(int i=0;i<=n;i++){
        G[i].clear();
        rG[i].clear();
    }
    memset(Index,0,sizeof Index);
    memset(point,0,sizeof point);
    load.clear();
    ans = k = 0;
}
void add_edge(int from,int to)
{
    G[from].push_back(to);
    rG[to].push_back(from);
}
void dfs(int now)
{
    vis[now] = 1;
    for(int i=0;i<G[now].size();i++){
        int nx = G[now][i];
        if(vis[nx]) continue;
        dfs(nx);
    }
    load.push_back(now);
}
void rdfs(int now,int num)
{
    vis[now] = 1;
    Index[now] = num;
    for(int i=0;i<rG[now].size();i++){
        int nx = rG[now][i];
        if(vis[nx]) continue;
        point[num].cost = min(point[num].cost,c[nx]);
        rdfs(nx,num);
        
    }
}
int main()
{
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%lf%lf%lf%d",&x[i],&y[i],&r[i],&c[i]);
        init();
        for(int i=1;i<=n;i++){
            for(int j=i+1;j<=n;j++){
                double dist = sqrt(pow(x[i]-x[j],2)+pow(y[i]-y[j],2));
                if(dist<=r[i]) add_edge(i, j);
                if(dist<=r[j]) add_edge(j, i);
            }
        }
        memset(vis,0,sizeof vis);
        for(int i=1;i<=n;i++) if(!vis[i]) dfs(i);
        memset(vis,0,sizeof vis);
        for(int i=(int)load.size()-1;i>=0;i--){
            int st = load[i];
            if(vis[st]) continue;
            point[++k].cost = c[st];
            rdfs(st,k);
        }
        memset(vis,0,sizeof vis);
        for(int i=1;i<=n;i++){
            for(int j=0;j<G[i].size();j++){
                int nx = G[i][j];
                if(Index[i]==Index[nx]) continue;
                point[Index[nx]].ru++;
            }
        }
        for(int i=1;i<=k;i++) if(point[i].ru==0) ans += point[i].cost;
        printf("Case #%d: %d\n",++cas,ans);
    }
    return 0;
}
 

                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值