hdu5934(tarjan算法+缩点)bomb

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 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
- 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
题目大意:给你n个炸弹的坐标,炸弹具有这样的性质:引爆第i炸弹需要花费一定的价值Ki,并且它的爆炸范围为ri,当你引爆一个炸弹时,在它爆炸范围内的炸弹也会爆炸,问最少需要花费多少,可以引爆所有炸弹。
解: 先找出图中所有强连通分量,因为在某个个分量中,所有的点可以互相到达,所以将其看为一个点,并记录这个分量中花费最少的炸弹费用,最后就形成了一张新
图,找出所有新图点中入度为零的点,也就是入度为零的分量,统计前面记录的这个分量中的最小值,便为结果。因为如果某个点的入度为零,就说明这个点无法被其他分量所引爆。
 
#include <iostream>  
#include <algorithm>   
#include <string.h>  
#include <math.h>
using namespace std; 
const int maxn=0x3f3f3f3f;
const int maxx=1010; 
typedef long long ll;
ll m,n,top,q,number,minn;  
int in[maxx],dfn[maxx],low[maxx],total[maxx],stack[maxx],master[maxx];
ll va[maxx];
int head[2*maxx];//maxx: 最大点数 
bool d[maxx]; 
struct  point{    
    int to;  
    int next; 
};point pt[2*maxx*maxx]; //边为点的平方大 
struct poi{
	ll x;
	ll y;
	ll r;
};
poi ppt[maxx];
void add(int u,int v)//建表 
{ 
        pt[q].next=head[u];  
        pt[q].to=v;  
        head[u]=q++;
}
int tarjan (int k)
{
	int i;
	dfn[k]=low[k]=++number; //设置dfn与low数组的初值; 
	stack[++top]=k; //将当前点压栈 
	d[k]=true;//表示 当前点已入栈; 
	for (i=head[k];i!=-1;i=pt[i].next)
	{
		if (!dfn[pt[i].to])
		{
			tarjan(pt[i].to);
			low[k]=min(low[k],low[pt[i].to]);
		}
		else if (d[pt[i].to]==true)
		low[k]=min(low[k],dfn[pt[i].to]); 
	}
	if (dfn[k]==low[k]) 
	{
		minn=maxn;
		while (1)
		{
			d[stack[top]]=false;
			int nu=stack[top--];
			master[nu]=k;
			if(va[nu]<minn)
			minn=va[nu];
			total[k]=minn;//找出此强连通分量的最大值,并且将值赋值给此强连通分量的主人所对应的total;
			if (stack[top+1]==k)break;
		}
	}
	return 0;
}
int main()  
{  

    int t,ans=1;
    cin>>t;
    while (t--)
    {
    int sum=0;
    number=top=0;
	q=1;
    memset(in,0,sizeof(in));  
    memset(total,0,sizeof(total));
	memset(dfn,0,sizeof(dfn)); 
	memset(stack,0,sizeof(stack));  
    memset(head,-1,sizeof(head)); 
    memset(low,0,sizeof(low));
    scanf("%d",&n);
    for (int i=1;i<=n;i++) //边 
    scanf("%lld%lld%lld%lld",&ppt[i].x,&ppt[i].y,&ppt[i].r,&va[i]);
    for (int i=1;i<=n;i++)
    {
    	for (int j=1;j<=n;j++)
    	{
    		if (i!=j)
    		{
    		    ll ans=(ppt[i].x-ppt[j].x)*(ppt[i].x-ppt[j].x)+(ppt[i].y-ppt[j].y)*(ppt[i].y-ppt[j].y);
    		    ll ans1=ppt[i].r*ppt[i].r;
    			if (ans<=ans1)
    			add(i,j);
			}
		}
	}
	for (int i=1;i<=n;i++)
     master[i]=i;
    for (int i=1;i<=n;i++)
    if (!dfn[i])tarjan(i);
     for (int i=1;i<=n;i++)
     {
     	for (int j=head[i];j!=-1;j=pt[j].next)
     	{
     	    int v=pt[j].to;
			 if (master[v]!=master[i])//如果两个相邻点的的主人不是一个,即在两个强连通分量中,直接将被指向的那个点的主人的入度++;
			 { 
			 	in[master[v]]++; 
			 }
		}
	 }
	 for (int i=1;i<=n;i++)
	 {
	 	if (master[i]==i&&!in[i])//如果入读为0并且是一个强连通分量的主人,统计最小值;
	 	sum+=total[i];
	 }
	 printf("Case #%d: %d\n",ans++,sum);
    }
	 return 0;
}  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值