http://acm.hdu.edu.cn/showproblem.php?pid=5934
题目大意:
有n个炸弹,给出他们的坐标(x,y)以及伤害半径r和引爆代价c。
在炸弹爆炸半径以内以及边缘上的炸弹会被连锁引爆。求最少需要多少的代价引爆所有的炸弹。
思路:
求scc缩点,然后产生若干个DAG,找到每个DAG得起点,对每个起点内的所有点找一个最小的代价点贡献给ans,累加求解就是答案,
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define pii pair<int,int> 4 #define mp make_pair 5 const int maxn=1005; 6 int T,N; 7 long long x[maxn],y[maxn],r[maxn],c[maxn]; 8 vector<int>g[maxn]; 9 int sum,scc_cnt; 10 int low[maxn],dfn[maxn],scc[maxn],in[maxn]; 11 stack<int>S; 12 bool ok(int i,int j){ 13 return (y[i]-y[j])*(y[i]-y[j])+(x[i]-x[j])*(x[i]-x[j])<=r[i]*r[i]; 14 } 15 void dfs(int u){ 16 low[u]=dfn[u]=++sum; 17 S.push(u); 18 for(int v:g[u]){ 19 if(!dfn[v]){ 20 dfs(v); 21 low[u]=min(low[u],low[v]); 22 }else if(!scc[v]) low[u]=min(low[u],dfn[v]); 23 } 24 if(low[u]==dfn[u]){ 25 ++scc_cnt; 26 int x=-1; 27 while(x!=u){ 28 x=S.top(); 29 S.pop(); 30 scc[x]=scc_cnt; 31 } 32 } 33 } 34 int main(){ 35 scanf("%d",&T); 36 for(int cas=1;cas<=T;++cas){ 37 cin>>N; 38 sum=scc_cnt=0; 39 while(!S.empty())S.pop(); 40 for(int i=1;i<=N;++i) 41 low[i]=dfn[i]=scc[i]=0, 42 g[i].clear(),scanf("%lld%lld%lld%lld",&x[i],&y[i],&r[i],&c[i]); 43 for(int i=1;i<=N;++i){ 44 for(int j=1;j<=N;++j){ 45 if(i==j)continue; 46 if(ok(i,j))g[i].push_back(j); 47 } 48 } 49 for(int i=1;i<=N;++i){ 50 if(!dfn[i])dfs(i); 51 }//puts("---"); 52 for(int i=1;i<=scc_cnt;++i)in[i]=0; 53 for(int i=1;i<=N;++i){ 54 for(int j:g[i]){ 55 if(scc[i]==scc[j])continue; 56 in[scc[j]]++; 57 } 58 } 59 long long ans=0; 60 for(int i=1;i<=scc_cnt;++i){ 61 if(in[i]==0){ 62 long long minc=99999999; 63 for(int j=1;j<=N;++j){ 64 if(scc[j]==i){ 65 minc=min(minc,c[j]); 66 } 67 } 68 ans+=minc; 69 } 70 } 71 cout<<"Case #"<<cas<<": "<<ans<<endl; 72 } 73 return 0; 74 }
-