题目:http://acm.hdu.edu.cn/showproblem.php?pid=5934
- 根据距离关系建边
- 对于强连通分量来说,只需引爆话费最小的炸弹即可引爆整个强连通分量
- 将所有的强连通分量缩成点,我们就得到了一棵树,我们只需要引爆树根的炸弹即可
- 我们可以处理出每个点所属的强连通分量的拓扑序,或者说染色法,把属于同一个强连通分量的点标上同一个数字
- 处理完强连通分量后,我们不需要建树,我们可以用并查集来维护,更好的办法是统计每个点的入度,入读为0即为根节点
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxv = 1111; 5 int V;//总共点的个数 6 vector<int> g[maxv]; 7 vector<int> rg[maxv]; 8 vector<int> vs; 9 bool used[maxv]; 10 int cmp[maxv];//保存拓扑序 11 ll cost[maxv];//每个拓扑序的话费 12 ll x[1111],y[1111],r[1111],c[1111]; 13 ////scc 14 void dfs(int v){ 15 used[v] = true; 16 for(int i = 0;i<g[v].size();i++) 17 if(!used[g[v][i]]) 18 dfs(g[v][i]); 19 vs.push_back(v); 20 } 21 void rdfs(int v,int k){ 22 used[v] = true; 23 cmp[v] = k; 24 cost[k] = min(cost[k],c[v]);//处理出每个强连通分量的最小话费 25 for(int i = 0;i<rg[v].size();i++) 26 if(!used[rg[v][i]]) 27 rdfs(rg[v][i],k); 28 } 29 int scc(){ 30 memset(used,0,sizeof(used)); 31 vs.clear(); 32 for(int v = 1;v<=V;v++)//这里要注意,下标是从0开始还是从1开始 33 if(!used[v]) 34 dfs(v); 35 memset(used,0,sizeof(used)); 36 int k = 1; 37 for(int i = vs.size()-1;i>=0;i--) 38 if(!used[vs[i]]) 39 rdfs(vs[i],k++); 40 return k; 41 } 42 ////// 43 void addedge(int i,int j){ 44 ll dis = (y[i]-y[j])*(y[i]-y[j])+(x[i]-x[j])*(x[i]-x[j]); 45 if(dis <= r[i]*r[i]){ 46 g[i].push_back(j); 47 rg[j].push_back(i); 48 } 49 if(dis <= r[j]*r[j]){ 50 g[j].push_back(i); 51 rg[i].push_back(j); 52 } 53 } 54 ////// 55 int du[1111]; 56 int main(){ 57 int t; 58 cin >> t; 59 int cas = 1; 60 while(t--){ 61 int n; 62 cin >> n; 63 V = n; 64 memset(cost,0x3f3f3f3f,sizeof(cost)); 65 for(int i = 1;i<=n;i++){ 66 g[i].clear(); 67 rg[i].clear(); 68 } 69 for(int i = 1;i<=n;i++){ 70 scanf("%I64d%I64d%I64d%I64d",&x[i],&y[i],&r[i],&c[i]); 71 for(int j = 1;j<i;j++){ 72 addedge(i,j); 73 } 74 } 75 int k = scc(); 76 memset(du,0,sizeof(du)); 77 for(int i = 1;i<=n;i++) 78 for(int j = 0;j<g[i].size();j++) 79 if(cmp[i] != cmp[g[i][j]])//拓扑序不同,度数加1 80 du[cmp[g[i][j]]]++; 81 ll ans = 0; 82 for(int i = 1;i<k;i++) 83 if(du[i] == 0) 84 ans += cost[i] ; 85 printf("Case #%d: %I64d ",cas++,ans); 86 } 87 return 0; 88 }