E - Bomb
【 解析 】
询问炸掉所有的炸弹的 cost ,那么
对于两个炸弹【 i,j 】 如果 i 爆炸后,可以让 j 也炸掉,那么就从 i 到 j 连一条边,表示 i (炸毁)则 j 可炸毁
(这样 cost 会减少的嘛——免费炸毁 j )
即 i 到 j 的距离 小于等于 i 所能 炸到 的 范围 (半径 )
i 到 j 的距离 用公式
![]()
(如果防止精度问题,可以同时平方,实际上,这题不存在 -_- )
1 . 如果 A->B->A 那么A-B形成环,炸毁A、B中任意一个炸弹,都可同时毁掉 A && B ,那么
我们 肯定 要选这个环里 最小的 点代价
2 . 解决 环 的情况之后,形成一个DAG(有向无环图)【 当然, 并 不 一定连通 】
3 . 显然可以得到:因为 1、2、3 号节点没有 别的节点 可以 帮忙 炸毁 它,所以他们一定要 自力更生 ,
-> 即一定 要 炸毁 (入度为 0 ) 的 它们
4 . 炸毁后:
发现 : 别的节点 已经 KO 了!!!
So:炸毁入度为 0 的点即是最少的 cost 。
(PS:为什么不炸毁别的点呢,别的点已经 KO 啦,我干嘛要增加 cost 呢?)
【实际上,我当时并没有想到,我想的是DAG上的DP,然后,图不连通,这怎么搞?】
【然后,翻出了题解,原来如此啊,,我还是太菜了 】
【关于数据】
边最多有
条( n是点数,单向边嘛)
真实数据中 没有 半径 < 0 的情况,担心的话 加个 特判好了
【 WA 的原因】
因为括号里先算,(LL)(int * int)这样的话里面算出来还是int,但是已经爆了,转化成 LL 也是没有用的
因而 WA 掉 (当然,你可用 sqrt )
所以这样写((LL)int * (LL)int) 才对,即使是(int * (LL)int)也是可以的啊,哭哭哭
至于 题面中 的 -1e8 < ri < 1e8 ,好像数据中是正常的,没有小于 0 的半径
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#define LL long long
using namespace std;
const int inf = 0x7f7f7f7f;
inline int wread(){
char c(getchar());int wans(0),flag(1);
while (c<'0' ||c>'9'){if (c=='-')flag=-1;c=getchar ();}
while (c>='0' && c<='9'){wans=wans*10+c-'0';c=getchar();}
return wans*=flag;
}
struct node2{int xi,yi,ri,ci;}scf[1007];
int K,hed[1007];
struct node{int u,v,nxt;}e[1000007];
void ad (int u,int v){e[++K].v=v;e[K].nxt=hed[u];hed[u]=K;}
int dfn[1007],low[1007],cnt,SCC;
int S[1007],top;
bool ins[1007];
int belong_v[1007],eve[1007];
vector <int> T_SCC[1007];
void Tarjan_SCC(int x){
dfn[x]=low[x]=++cnt;
ins[x]=true;
S[++top]=x;
for (int i(hed[x]);i!=-1;i=e[i].nxt){
int v(e[i].v);
if (!dfn[v]){
Tarjan_SCC(v);
low[x]=min (low[x],low[v]);
}
else if (ins[v]) low[x]=min (low[x],dfn[v]);
}
if (dfn[x]==low[x]){
SCC++;
int y;
do{
y=S[top--];
ins[y]=false;
T_SCC[SCC].push_back(y);
belong_v[y]=SCC;
}while (x!=y);
}
}
int num_v[1007];//统计每个SCC的入度
void re_build(){
for (int A(1);A<=SCC;++A){
eve[A]=inf;
for (int B(0); B<T_SCC[A].size(); ++B){
int u(T_SCC[A][B]);
eve[A]=min (eve[A], scf[u].ci);
for (int i(hed[u]);i!=-1;i=e[i].nxt){
int v(e[i].v);
if (belong_v[v]==A) continue;
num_v[belong_v[v]]++;
}
}
}
}
int main (){
int F(0);
int T(wread());
while (T--){
F++;
int n(wread());
//初始化
for (int i(1);i<=n;++i)
hed[i]=-1,dfn[i]=low[i]=ins[i]=num_v[i]=0,T_SCC[i].clear();
K=cnt=top=SCC=0;
//读入
for (int i(1);i<=n;++i)
scf[i].xi=wread(), scf[i].yi=wread(), scf[i].ri=wread(), scf[i].ci=wread();
//连边
for (int i=1;i<=n;++i)
for (int j=1;j<=n;++j){
if (i==j) continue;
LL ti1=((LL)scf[i].xi-(LL)scf[j].xi);
ti1*=ti1;
ti1+=((LL)scf[i].yi-(LL)scf[j].yi)*((LL)scf[i].yi-(LL)scf[j].yi);
if (ti1<=((LL)scf[i].ri*(LL)scf[i].ri)) ad(i,j);
}
for (int i(1);i<=n;++i)
if (!dfn[i])
Tarjan_SCC(i);
//统计新图入度为 0 的点 不需要重新建图
re_build();
//统计答案
int ans(0);
for (int i(1);i<=SCC;++i)
if (num_v[i]==0) ans+=eve[i];
//输出
printf("Case #%d: %d\n",F,ans);
}
return 0;
}