Each bomb has three attributes: exploding radius riri, position (xi,yi)(xi,yi) and lighting-cost cici which means you need to pay cici 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.
Every test case begins with an integers NN, which indicates the numbers of bombs.
In the following NN lines, the ith line contains four intergers xixi, yiyi, riri and cici, indicating the coordinate of ith bomb is (xi,yi)(xi,yi), exploding radius is riri and lighting-cost is cici.
Limits
- 1≤T≤201≤T≤20
- 1≤N≤10001≤N≤1000
- −108≤xi,yi,ri≤108−108≤xi,yi,ri≤108
- 1≤ci≤1041≤ci≤104OutputFor 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 4Sample Output
Case #1: 15
代碼:
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
using namespace std;
#define LL long long
#define N 2000
class Bomb //數據
{
public:
long long x,y,r,c;
}bo[1050];
int n; //點的個數
stack<int>sta; // 存儲已遍歷的結點
vector<int>gra[N]; // 鄰接表表示圖
int dfn[N]; // 深度優先搜索訪問次序
int low[N]; // 能追溯到的最早的次序
int InStack[N]; // 檢查是否在棧中(2爲在棧中,1爲已訪問,且不在棧中,0爲不在)
vector<int> Component[N]; // 獲得強連通分量結果
int InComponent[N]; // 記錄每個點在第幾號強連通分量裏
int index,ComponentNumber; // 索引號,強連通分量個數
LL cost[N]; // 縮點後每個縮點的最小花費
int rudu[N]; //入度,此題入度爲0的點是必須點燃的Bomb
void Pre_Processing()
{
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(InStack,0,sizeof(InStack));
memset(InComponent,0,sizeof(InComponent));
memset(rudu,0,sizeof(rudu));
memset(cost,0x3f3f3f3f,sizeof(cost));
index=ComponentNumber=0;
for(int i=0;i<=n;i++)
{
gra[i].clear();
Component[i].clear();
}
while(!sta.empty())
{
sta.pop();
}
}
bool judge(LL x1,LL y1,LL x2,LL y2,LL r1)
{
if((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)<=r1*r1)
return true;
else
return false;
}
void input()
{
cin>>n;
Pre_Processing();
for(int i=1;i<=n;i++)
{
cin>>bo[i].x>>bo[i].y>>bo[i].r>>bo[i].c;
}
for(int i=1;i<n;i++)
{
for(int j=i+1;j<=n;j++)
{
if(judge(bo[i].x,bo[i].y,bo[j].x,bo[j].y,bo[i].r)) gra[i].push_back(j);
if(judge(bo[i].x,bo[i].y,bo[j].x,bo[j].y,bo[j].r)) gra[j].push_back(i);
}
}
}
void tarjan(int u)
{
InStack[u]=2;
dfn[u]=low[u]=++index;
sta.push(u);
for(int i=0;i<gra[u].size();i++)
{
int t=gra[u][i];
if(dfn[t]==0)
{
tarjan(t);
low[u]=min(low[t],low[u]);
}
else if(InStack[t]==2)
{
low[u]=min(low[u],dfn[t]);
}
}
if(low[u]==dfn[u])
{
++ComponentNumber;
while(!sta.empty())
{
int j=sta.top();
sta.pop();
InStack[j]=1;
Component[ComponentNumber].push_back(j);
InComponent[j]=ComponentNumber;
cost[ComponentNumber]=min(bo[j].c,cost[ComponentNumber]);//記錄每個縮點的最小花費
if(j==u)
{
break;
}
}
}
}
int solve()
{
for(int i=1;i<=n;i++)
{
if(!dfn[i])
{
tarjan(i);
}
}
for(int i=1;i<=n;i++)//找出縮點後的入度
{
for(int j=0;j<gra[i].size();j++)
{
int q=gra[i][j];
if(InComponent[i]!=InComponent[q])
rudu[InComponent[q]]++;
}
}
int ans=0;
for(int i=1;i<=ComponentNumber;i++)
{
if(rudu[i]==0)
{
ans=cost[i]+ans;
}
}
return ans;
}
int main()
{
int T;
cin>>T;
for(int t=1;t<=T;t++)
{
input();
cout<<"Case #"<<t<<": "<<solve()<<endl;
}
return 0;
}