您的位置:首页 > 其它

Tarjan 缩点——HDU 5934

2017-05-06 10:38 323 查看
链接:http://acm.hdu.edu.cn/showproblem.php?pid=5934

题意:给出N个炸弹的坐标爆炸半径还有引爆的花费,求爆炸所有炸弹所需要的最小花费。

分析:我们发现如果炸弹A在B的爆炸范围内,同时炸弹B也在炸弹A的爆炸范围内,那么无论引爆哪一个,都会导致它们俩都爆炸,所以我们可以把A和B当做一个炸弹,花费为最小花费即可。同理,可以延伸到 n 个炸弹,如果引爆这 n 个炸弹中的任意一个,最终都会导致这 n 个炸弹都爆炸,那么也可以把这 n 个炸弹都用一个来替代,并用其中的最小花费来表示。这一步,我们可以用Tarjan缩点来完成。

建边:如果炸弹A能引爆炸弹B,那么建立一条有向边 A→B 。那么在求联通分量退栈的时候,找出最小花费,标记给这个连通块的。然后结束后,我们枚举每一条边,如果它们不在一个联通块里,我们就给指向的那个联通块增加一个入度。最终的花费就是所有入度为0的联通块(必须要引爆的炸弹)的花费和了。

AC代码:

/*************************************************************************
> File Name: B.cpp
> Author: Akira
> Mail: qaq.febr2.qaq@gmail.com
> Created Time: 2017年05月05日 星期五 19时37分48秒
************************************************************************/

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<stack>
#include<map>
#include<cmath>
#include<vector>
#include<set>
#include<list>
#include<ctime>
typedef long long LL;
typedef unsigned long long ULL;
typedef long double LD;
#define MST(a,b) memset(a,b,sizeof(a))
#define CLR(a) MST(a,0)
#define Sqr(a) ((a)*(a))

using namespace std;

#define MaxN 1010
#define MaxM MaxN*1000
#define INF 0x3f3f3f3f
#define PI 3.1415926535897932384626
const int mod = 1e9+7;
const int eps = 1e-8;
#define bug cout << 88888888 << endl;

struct Node
{
int x,y,r,c;
}node[MaxN];

int T,N;

struct Edge
{
int u,v,next;
}edge[MaxM],e[MaxM];
int cont, head[MaxN];
void add(int u, int v)
{
edge[cont].u = u;
edge[cont].v = v;
edge[cont].next = head[u];
head[u] = cont++;
}

int low[MaxN], dfn[MaxN];
int Stack[MaxN], top;
int belong[MaxN];
int vis[MaxN];
int Index, cnt;
int cost[MaxN];
void init()
{
cont = 0;
MST(head,-1);

MST(cost,INF);
MST(dfn, -1);
CLR(low);
CLR(vis);
Index = cnt = 1;
top = 0;
}
void Tarjan(int x)
{
low[x] = dfn[x] = Index;
Index++;
Stack[++top] = x;
vis[x] = true;
for(int i=head[x];i!=-1;i=edge[i].next)
{
int v = edge[i].v;
if(dfn[v] == -1)
{
Tarjan(v);
low[x] = min(low[x], low[v]);
}
else if(vis[v])
{
low[x] = min(low[x], dfn[v]);
}
}
if( low[x] == dfn[x] )
{
for(int v = -1;v!=x;top--)
{
v = Stack[top];
vis[v] = false;
belong[v] = cnt;
cost[cnt] = min(cost[cnt], node[v].c);
}
cnt++;
}
}
int in[MaxN];

void solve(int t)
{
init();
for(int i=1;i<=N;i++)
{
int xi = node[i].x;
int yi = node[i].y;
int ri = node[i].r;
for(int j=1;j<=N;j++)
{
if(i==j) continue;
LL dis = Sqr((LL)(node[j].x-xi)) + Sqr((LL)(node[j].y-yi));
if( dis<=Sqr((LL)ri) )
{
add(i,j);
//cout << i << " " << j << endl;
}
}
}
for(int i=1;i<=N;i++)
if(dfn[i]==-1)
Tarjan(i);

CLR(in);
for(int i=0;i<cont;i++)
{
int u = edge[i].u;
int v = edge[i].v;
if(belong[u] != belong[v])
{
//cout << u << ": " << belong[u] << endl;
//cout << v << ": " << belong[v] << endl;
in[belong[v]]++;
}
}
int ans = 0;
for(int i=1;i<cnt;i++)
{
//cout << in[i] << endl;
if(in[i]==0) ans += cost[i];
}
printf("Case #%d: %d\n",  t, ans);

}

int main()
{
scanf("%d", &T);
for(int t=1;t<=T;t++)
{
scanf("%d", &N);
for(int i=1;i<=N;i++) scanf("%d%d%d%d", &node[i].x, &node[i].y, &node[i].r, &node[i].c);
solve(t);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: