Time Limit: 40000/20000 MS (Java/Others)
Memory Limit: 32768/132768 K (Java/Others)
Problem Description
度度熊国王率领着喵哈哈族的勇士,准备进攻哗啦啦族。
哗啦啦族是一个强悍的民族,里面有充满智慧的谋士,拥有无穷力量的战士。
所以这一场战争,将会十分艰难。
为了更好的进攻哗啦啦族,度度熊决定首先应该从内部瓦解哗啦啦族。
第一步就是应该使得哗啦啦族内部不能同心齐力,需要内部有间隙。
哗啦啦族一共有
n
n
n个将领,他们一共有
m
m
m个强关系,摧毁每一个强关系都需要一定的代价。
现在度度熊命令你需要摧毁一些强关系,使得内部的将领,不能通过这些强关系,连成一个完整的连通块,以保证战争的顺利进行。
请问最少应该付出多少的代价。
Input
本题包含若干组测试数据。
第一行两个整数
n
,
m
n,m
n,m,表示有
n
n
n个将领,
m
m
m个关系。
接下来
m
m
m行,每行三个整数
u
,
v
,
w
u,v,w
u,v,w。表示u将领和v将领之间存在一个强关系,摧毁这个强关系需要代价
w
w
w
数据范围:
2
<
=
n
<
=
3000
2<=n<=3000
2<=n<=3000
1
<
=
m
<
=
100000
1<=m<=100000
1<=m<=100000
1
<
=
u
,
v
<
=
n
1<=u,v<=n
1<=u,v<=n
1
<
=
w
<
=
1000
1<=w<=1000
1<=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;
}