HDU 5934 && 2016CCPC杭州 B: Bomb(Trajan强连通)



题意:

坐标系上有n个炸弹,每个炸弹都有不同的爆炸半径,并且爆炸会引起连锁反应,如果一个炸弹爆炸,那么在这个炸弹的爆炸半径内所有的炸弹都会跟着引爆,你要引爆所有的炸弹,引爆每个炸弹都有不同的引爆代价,求最小代价


如果B在A的爆炸半径内,那么A到B连接一条有向边

之后强连通分量+缩点形成一张有向无环图

很显然只要点燃所有入度为0的点中最便宜的炸弹就好了

#include<stdio.h>
#include<string.h>
#include<vector>
#include<stack>
#include<algorithm>
using namespace std;
#define LL long long
vector<LL> G[1005], Gp[1005];
stack<LL> st;
typedef struct
{
	LL x;
	LL y;
	LL r;
	LL pri;
}Point;
Point s[1005];
LL t, cnt, time[1005], low[1005], vis[1005], scc[1005], cost[1005];
void Trajan(LL x)
{
	LL i, v;
	vis[x] = 1;
	low[x] = time[x] = ++t;
	st.push(x);
	for(i=0;i<G[x].size();i++)
	{
		v = G[x][i];
		if(vis[v]==0)
		{
			Trajan(v);
			low[x] = min(low[x], low[v]);
		}
		else if(scc[v]==0)
			low[x] = min(low[x], time[v]);
	}
	if(low[x]==time[x])
	{
		cnt++;
		while(st.empty()==0)
		{
			v = st.top();
			st.pop();
			scc[v] = cnt;
			cost[cnt] = min(cost[cnt], s[v].pri);
			if(v==x)
				break;
		}
	}
}
void Sech(LL x)
{
	LL i, v;
	vis[x] = 1;
	for(i=0;i<Gp[x].size();i++)
	{
		v = Gp[x][i];
		if(vis[v]==0)
			Sech(v);
	}
}
int main(void)
{
	LL T, n, i, j, v, ans, cas = 1;
	scanf("%lld", &T);
	while(T--)
	{
		scanf("%lld", &n);
		for(i=1;i<=n;i++)
		{
			G[i].clear();
			Gp[i].clear();
			scanf("%lld%lld%lld%lld", &s[i].x, &s[i].y, &s[i].r, &s[i].pri);
		}
		for(i=1;i<=n;i++)
		{
			for(j=1;j<=n;j++)
			{
				if(i==j)
					continue;
				if((s[i].x-s[j].x)*(s[i].x-s[j].x)+(s[i].y-s[j].y)*(s[i].y-s[j].y)<=s[i].r*s[i].r)
					G[i].push_back(j);
			}
		}
		cnt = t = 0;
		memset(vis, 0, sizeof(vis));
		memset(scc, 0, sizeof(scc));
		memset(cost, 62, sizeof(cost));
		for(i=1;i<=n;i++)
		{
			if(vis[i]==0)
				Trajan(i);
		}
		for(i=1;i<=n;i++)
		{
			for(j=0;j<G[i].size();j++)
			{
				v = G[i][j];
				if(scc[i]!=scc[v])
					Gp[scc[i]].push_back(scc[v]);
			}
		}
		ans = 0;
		memset(vis, 0, sizeof(vis));
		for(i=cnt;i>=1;i--)
		{
			if(vis[i]==0)
			{
				ans += cost[i];
				Sech(i);
			}
		}
		printf("Case #%lld: %lld\n", cas++, ans);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值