HDU 5934 Bomb(tarjan/SCC縮點)題解

思路:建一個有向圖,指向能引爆對象,把強連通分量縮成一點,只要點燃圖中入度爲0的點即可。因爲入度爲0沒人能引爆,不爲0可以由別人引爆。

思路很簡單,但是早上寫的一直錯,改了半天了,推倒重來才過了...

#include<cstdio>
#include<set>
#include<stack>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn = 1000+5;
const int INF = 0x3f3f3f3f;
int head[maxn],dfn[maxn],low[maxn],vis[maxn],in[maxn],scc[maxn],val[maxn];
int tot,scc_int,index;
stack<int> st;
struct Edge{
    int u,v,next;
}e[maxn*maxn];
struct Node{
    ll x,y;
    ll r,c;
}p[maxn];

void addEdge(int u,int v){
    e[tot].u = u;
    e[tot].v = v;
    e[tot].next = head[u];
    head[u] = tot++;
}

void tarjan(int u){
    vis[u] = 1;
    dfn[u] = low[u] = ++index;
    st.push(u);
    for(int i = head[u];i != -1;i = e[i].next){
        int v = e[i].v;
        if(!dfn[v]){
            tarjan(v);
            low[u] = min(low[u],low[v]);
        }
        else if(vis[v]){
            low[u] = min(low[u],dfn[v]);
        }
    }
    if(dfn[u] == low[u]){
        scc_int++;
        ll MIN = INF;
        int v;
        do{
            v = st.top();
            st.pop();
            vis[v] = 0;
            scc[v] = scc_int;
            MIN = min(MIN,p[v].c);
        }while(v != u);
        val[scc_int] = MIN;
    }
}
void init(){
    tot = scc_int = index = 0;
    while(!st.empty()) st.pop();
    memset(head,-1,sizeof(head));
    memset(dfn,0,sizeof(dfn));
    memset(vis,0,sizeof(vis));
    memset(in,0,sizeof(in));
}
int main(){
    int T,n,Case = 1;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        init();
        for(int i = 1;i <= n;i++)
            scanf("%lld%lld%lld%lld",&p[i].x,&p[i].y,&p[i].r,&p[i].c);
        for(int i = 1;i <= n;i++){
            for(int j = i + 1;j <= n;j++){
                ll dis = (p[i].x - p[j].x)*(p[i].x - p[j].x) + (p[i].y - p[j].y)*(p[i].y - p[j].y);
                if(p[i].r*p[i].r >= dis){
                    addEdge(i,j);
                }
                if(p[j].r*p[j].r >= dis){
                    addEdge(j,i);
                }
            }
        }
        for(int i = 1;i <= n;i++){
            if(!dfn[i])
                tarjan(i);
        }
        for(int i = 1; i<= n;i++){
            for(int j = head[i];~j;j = e[j].next){
                int v = e[j].v;
                if(scc[i] != scc[v]){
                    in[scc[v]]++;
                }
            }
        }
        ll ans = 0;
        for(int i = 1;i <= scc_int;i++){
            if(in[i] == 0){
                ans += val[i];
            }
        }
        printf("Case #%d: %lld\n",Case++,ans);
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章