HDU 5934 && 2016CCPC杭州 B: Bomb(Trajan强连通)
程序员文章站
2022-04-28 14:49:09
...
题意:
坐标系上有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;
}