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.
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
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
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;
}