Time Limit: 40000/20000 MS (Java/Others)
Memory Limit: 32768/132768 K (Java/Others)
Problem Description
度度熊國王率領着喵哈哈族的勇士,準備進攻嘩啦啦族。
嘩啦啦族是一個強悍的民族,裏面有充滿智慧的謀士,擁有無窮力量的戰士。
所以這一場戰爭,將會十分艱難。
爲了更好的進攻嘩啦啦族,度度熊決定首先應該從內部瓦解嘩啦啦族。
第一步就是應該使得嘩啦啦族內部不能同心齊力,需要內部有間隙。
嘩啦啦族一共有個將領,他們一共有個強關係,摧毀每一個強關係都需要一定的代價。
現在度度熊命令你需要摧毀一些強關係,使得內部的將領,不能通過這些強關係,連成一個完整的連通塊,以保證戰爭的順利進行。
請問最少應該付出多少的代價。
Input
本題包含若干組測試數據。
第一行兩個整數,表示有個將領,個關係。
接下來行,每行三個整數。表示u將領和v將領之間存在一個強關係,摧毀這個強關係需要代價
數據範圍:
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;
}