CQOI 2016 不同的最小割

题目大意:一个无向图,求所有点对不同的最小割种类数

最小割最多有n-1个,这n-1个最小割构成一个最小割树

分治法寻找n-1个最小割。对于当前点集X,任选两点为ST做最小割,然后找出与S相连的所有点和与T相连的所有点构成S集与T集,更新S集与T集的最小割。然后递归处理两个集合。

最后将最小割排序,找出有多少不同最小割即可

#include
#define inf 0x7ffffff
using namespace std;
inline int read(){
    int s=0;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar());
    for(;ch>='0'&&ch<='9';ch=getchar())s=s*10+ch-'0';
    return s;
}
struct edge{
    int to,next;
    int cap;
}G[20010];
int tot=1,h[1000],S,T;
void add(int x,int y,int z){
    tot++;G[tot].to=y;G[tot].next=h[x];G[tot].cap=z;h[x]=tot;
}
int vis[1000],mark[1000];
int a[1000];
int n,m;
set<int>s;
bool bfs(){
    memset(vis,0,sizeof(vis));
    queue<int>Q;Q.push(S);vis[S]=1;
    while(!Q.empty()){
        int u=Q.front();Q.pop();
        for(int i=h[u];i;i=G[i].next){
            int v=G[i].to;
            if(vis[v]||G[i].cap<=0)continue;
            vis[v]=vis[u]+1;
            Q.push(v);
        }
    }return vis[T];
}
int dfs(int u,int w){
    if(u==T||w==0)return w;
    int flow=0;
    for(int i=h[u];i;i=G[i].next){
        int v=G[i].to;
        if(vis[v]!=vis[u]+1||G[i].cap<=0)continue;
        if(int t=dfs(v,min(w,G[i].cap))){
            G[i].cap-=t;G[i^1].cap+=t;
            flow+=t;w-=t;
            if(!w)break;
        }
    }
    if(!flow)vis[u]=0;
    return flow;
}
int dinic(){
    int f=0;
    while(bfs())f+=dfs(S,inf);
    return f;
}
void dfs(int x){
    mark[x]=1;
    for(int i=h[x];i;i=G[i].next)
        if(G[i].cap&&!mark[G[i].to])
            dfs(G[i].to);
}
void clear(){
    for(int i=2;i<=tot;i+=2)
        G[i].cap=G[i^1].cap=(G[i].cap+G[i^1].cap)/2;
}
int tmp[1000];
void solve(int l,int r){
    if(l==r)return;
    clear();
    S=a[l],T=a[r];
    int t=dinic();
    s.insert(t);
    memset(mark,0,sizeof(mark));
    dfs(S);
    int L=l,R=r;
    for(int i=l;i<=r;++i)
        if(mark[a[i]])tmp[L++]=a[i];
        else tmp[R--]=a[i];
    for(int i=l;i<=r;++i)a[i]=tmp[i];
    solve(l,L-1);solve(R+1,r);
}
int main(){
    n=read();m=read();
    for(int i=1;i<=m;++i){
        int u=read(),v=read(),w=read();
        add(u,v,w);add(v,u,w);
    }
    for(int i=1;i<=n;++i)a[i]=i;
    solve(1,n);
    printf("%d\n",s.size());
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/117208-/p/5381700.html

你可能感兴趣的:(CQOI 2016 不同的最小割)