[HDU6081]度度熊的王國戰略

Time Limit: 40000/20000 MS (Java/Others)
Memory Limit: 32768/132768 K (Java/Others)

Problem Description
度度熊國王率領着喵哈哈族的勇士,準備進攻嘩啦啦族。
嘩啦啦族是一個強悍的民族,裏面有充滿智慧的謀士,擁有無窮力量的戰士。
所以這一場戰爭,將會十分艱難。
爲了更好的進攻嘩啦啦族,度度熊決定首先應該從內部瓦解嘩啦啦族。
第一步就是應該使得嘩啦啦族內部不能同心齊力,需要內部有間隙。
嘩啦啦族一共有nn個將領,他們一共有mm個強關係,摧毀每一個強關係都需要一定的代價。
現在度度熊命令你需要摧毀一些強關係,使得內部的將領,不能通過這些強關係,連成一個完整的連通塊,以保證戰爭的順利進行。
請問最少應該付出多少的代價。

Input
本題包含若干組測試數據。
第一行兩個整數nmn,m,表示有nn個將領,mm個關係。
接下來mm行,每行三個整數u,v,wu,v,w。表示u將領和v將領之間存在一個強關係,摧毀這個強關係需要代價ww

數據範圍:
2<=n<=30002<=n<=3000
1<=m<=1000001<=m<=100000
1<=u,v<=n1<=u,v<=n
1<=w<=10001<=w<=1000

Output
對於每組測試數據,輸出最小需要的代價。

Sample Input

2 1
1 2 1
3 3
1 2 5
1 2 4
2 3 3

Sample Output

1
3

題解:
全局最小割裸題

全局最小割的實現:
1.先選出G中的某對點s-t的最小割,更新一下答案。
2.將選出的s-t合併到一個集合中。
3.反覆這麼做,直到G只剩下一個頂點。

如何找到當前狀態下的最小割?
1.先隨便選一個起點(或合併之後的集合)。
2.以這個起點開始,遍歷所有與這個點(集合)相鄰的其他點(集合)
3.用大根堆存儲被連接的集合,最後直接把最後加入剩下的那個點和最後拓展的那個點union到一個集合裏面就行。

#include<bits/stdc++.h>
#define ll long long
#define pa pair<ll,int>
using namespace std;
const ll INF=1e18;
struct edge{
    int to,w;
};
int n,m;
vector<edge>G[3004];
int f[3004],lk[3004];
int Find(int x){return f[x]==x?x:f[x]=Find(f[x]);}
void Union(int x,int y){
    int p=x;
    while(lk[p])p=lk[p];
    lk[p]=y;
    f[y]=x;
}
ll val[3004];
bool vis[3004];
priority_queue<pa>q;
ll msp(int cnt,int &s,int &t){
    for(int i=1;i<=n;i++){
        vis[i]=0;
        val[i]=0;
    }
    while(!q.empty())q.pop();
    t=1;
    while(--cnt){
        vis[t]=1;
        s=t;
        for(int x=s;x;x=lk[x]){
            for(int i=0;i<G[x].size();i++){
                int to=Find(G[x][i].to),w=G[x][i].w;
                if(!vis[to]){
                    val[to]+=w;
                    q.push({val[to],to});
                }
            }
        }
        t=0;
        while(!t){
            if(q.empty())return 0;
            ll ft=q.top().first;
            int st=q.top().second;
            q.pop();
            if(val[st]==ft){
                t=st;
            }
        }
    }
    return val[t];
}
ll StoerWanger(){
    ll ans=INF;
    int s,t;
    for(int i=n;i>1;i--){
        ans=min(ans,msp(i,s,t));
        if(ans==0)break;
        Union(s,t);
    }
    return ans;
}
int w33ha(){
    for(int i=1;i<=n;i++){
        f[i]=i;
        lk[i]=0;
        G[i].clear();
    }
    for(int i=1;i<=m;i++){
        int u,v,w;scanf("%d%d%d",&u,&v,&w);
        G[u].push_back((edge){v,w});
        G[v].push_back((edge){u,w});
    }
    printf("%lld\n",StoerWanger());
    return 0;
}
int main(){
    while(scanf("%d%d",&n,&m)!=EOF)w33ha();
    return 0;
}

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