Bomb HDU - 5934 强联通图,连通分量tarjan算法(模板)

There are  NN bombs needing exploding. 

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.
InputFirst line contains an integer  TT, which indicates the number of test cases. 

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  xixiyiyiriri and  cici, indicating the coordinate of ith bomb is  (xi,yi)(xi,yi), exploding radius is  riri and lighting-cost is  cici

Limits 
1T201≤T≤20 
1N10001≤N≤1000 
108xi,yi,ri108−108≤xi,yi,ri≤108 
1ci1041≤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 4
Sample 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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值