[HDU 5934]Bomb

假如想象 提交于 2019-11-27 12:52:51

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5934
题面
在这里插入图片描述题意
题目是说有NN个炸弹,每个炸弹有其对应的坐标(xix_i,yiy_i)、爆炸半径rir_i以及引爆其所需的费用costicost_i,当一个炸弹爆炸时在其爆炸半径内其它未爆炸的炸弹也会爆炸。问使所有炸弹爆炸的最小费用是多少。

思路
显然我们可以把炸弹之间的引爆关系看成有向边(因为存在爆炸半径,所以A可以引爆B不一定B可以引爆A)把炸弹看成图中的点,问题就转化成了,图中有NN个点以及若干条有向边,选取第ii个点的费用是cic_i,问选取若干个点使得图中每个点都可到达所需的最小费用是多少?
有向图中可能存在强连通分量,考虑每个强连通分量的最小代价必然是强连通分量中代价最小的点,我们可以将每个强连通分量用其中代价最小的点代替,再重新建图,这时若存在A指向B的关系,显然B就可以不用选了。
故完整算法就是:

  • 读入所有点的数据,暴力建图
  • 找强连通分量,把所有强连通分量的代价用其中代价最小的点代替
  • 重新建图
  • 找出所有入度为0的点,把代价加起来即得答案。

顺便吐槽一下HDOJ越界了居然返回TLE
在这里插入图片描述在这里插入图片描述
AC代码

#include<stdio.h>
#include<stack>
#include<algorithm>
typedef long long LL;
using namespace std;
stack<int>sta;
int head[1005],c[1005],nxt[3005050],p[3005050],vis[1005],dfn[1005],low[1005],f[1005];
int rd[1005],mi[1005];
int t,cot,n,cnt,Case=0,ans=0;
LL x[1005],y[1005],r[1005];
void dfs(int now)
{
	sta.push(now);
	for(int i=head[now];i;i=nxt[i])
	{
		if(vis[p[i]]!=t)
		{
			vis[p[i]]=t;dfn[p[i]]=low[p[i]]=dfn[now]+1;
			dfs(p[i]);
			low[now]=min(low[now],low[p[i]]);
		}else
		if(!f[p[i]]) low[now]=min(low[now],low[p[i]]);
	}
	if(dfn[now]==low[now])
	{
		++cot;
		while(sta.top()!=now)
		{
			f[sta.top()]=cot;
			sta.pop();
		}
		f[sta.top()]=cot;
		sta.pop();
	}
	return;
}
int main()
{
	scanf("%d",&t);
	while(t)
	{
		Case++;
		for(int i=1;i<=n;i++)head[i]=0,f[i]=0,dfn[i]=0,low[i]=0;
		for(int i=1;i<=cot;i++)rd[i]=0,mi[i]=0;
		cnt=0;cot=0;
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
		{
			scanf("%lld%lld%lld%d",&x[i],&y[i],&r[i],&c[i]);
		}
		for(int i=1;i<n;i++)
		for(int j=i+1;j<=n;j++)
		{
			if((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])<=r[i]*r[i])
			{
				p[++cnt]=j;nxt[cnt]=head[i];head[i]=cnt;
			}
			if((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])<=r[j]*r[j])
			{
				p[++cnt]=i;nxt[cnt]=head[j];head[j]=cnt;
			}
		}
		for(int i=1;i<=n;i++)
		if(vis[i]!=t)
		{
			vis[i]=t;
			dfn[i]=1;low[i]=1;
			dfs(i);
		}
		//找所有强连通分量
		for(int i=1;i<=n;i++)
		{
			if((!mi[f[i]])||mi[f[i]]>c[i])mi[f[i]]=c[i];
			for(int j=head[i];j;j=nxt[j])
			if(f[i]!=f[p[j]])
			{
				rd[f[p[j]]]++;
			}
		}//以找到的强联通分量重新建图,计算入度
		ans=0;
		for(int i=1;i<=cot;i++)if(!rd[i])ans+=mi[i];
		printf("Case #%d: %d\n",Case,ans);
		t--;
	}
	return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!