网络流(3)——最小割树

来源:互联网 发布:淘宝针织衫 编辑:程序博客网 时间:2024/05/29 08:53

啊,学渣苦,学渣累

什么是最小割树

emm…
可以通过不需要做nn次网络流求出n个节点间两两网络流的O()玄学算法

怎么做

分治。
首先我们随机选S,T跑一遍最小割
然后原图就被分为了与S连通的s集以及与T联通的t集。
然后分治s集,t集,随缘分治(笑)
据说能证明,然而并不会。
其实连带更新是O(n3logn)
局部代码长这样

void mergesort(int l,int r){    if(l==r) return ;    for(int i=2;i<=tot;i+=2)        wide[i]=wide[i^1]=(wide[i]+wide[i^1])>>1;    S=id[l];T=id[r];     tmpflow=solve();    memset(vis,false,sizeof(vis));    dfs(S);    for(int i=1;i<=n;++i)        if(vis[i])            for(int j=1;j<=n;++j)                if(!vis[j])                    flowsze[i][j]=flowsze[j][i]=min(tmpflow,flowsze[i][j]);    int lef=l,righ=r;    for(int i=l;i<=r;++i)        if(vis[id[i]])            tmp[lef++]=id[i];        else            tmp[righ--]=id[i];    for(int i=l;i<=r;++i)        id[i]=tmp[i];    if(lef!=l)        mergesort(l,lef-1);    if(righ!=r)        mergesort(righ+1,r);}

习题

(1)最小割(ZJOI2011)
——“有限次数询问,求有多少点对的最小割小于给定值”
——“这不是裸题么”

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<string>#include<ctime>#include<cmath>#include<algorithm>#include<cctype>#include<iomanip>#include<queue>using namespace std;inline int read(){    int i=0,f=1;    char ch;    for(ch=getchar();!isdigit(ch);ch=getchar())        if(ch=='-') f=-1;    for(;isdigit(ch);ch=getchar())        i=(i<<3)+(i<<1)+(ch^48);    return i*f;}int buf[1024];inline void write(int x){    if(!x){putchar('0');return ;}    if(x<0){putchar('-');x=-x;}    while(x){buf[++buf[0]]=x%10,x/=10;}    while(buf[0]) putchar(buf[buf[0]--]+48);    return ;}#define stan 222#define sten 7777int tot,first[stan],nxt[sten],goal[sten],wide[sten];int tmp[stan],id[stan],flowsze[stan][stan],ans,n,m,q,tmpflow,a,b,c;int S,T,level[stan];bool vis[stan];queue<int>que;void addedge(int a,int b,int c){    nxt[++tot]=first[a];first[a]=tot;goal[tot]=b;wide[tot]=c;    nxt[++tot]=first[b];first[b]=tot;goal[tot]=a;wide[tot]=c;    return ;}bool bfs(){    while(!que.empty()) que.pop();    for(int i=1;i<=n;++i)        level[i]=-1;    level[S]=0;que.push(S);     while(!que.empty()){        int u=que.front();que.pop();        for(int p=first[u];p;p=nxt[p])            if(wide[p]&&level[goal[p]]==-1){                level[goal[p]]=level[u]+1;                if(goal[p]==T) return true;                que.push(goal[p]);             }    }    return false;}int dfs(int u,int flow){    if(u==T) return flow;    int ret=0,data;    for(int p=first[u];p;p=nxt[p])        if(wide[p]&&level[goal[p]]==level[u]+1){            data=dfs(goal[p],min(flow-ret,wide[p]));            if(data){                wide[p]-=data;                wide[p^1]+=data;                ret+=data;                if(ret==flow) return ret;             }        }    level[u]=-1;    return ret;}int solve(){    int ret=0;    while(bfs())        ret+=dfs(S,999999999);    return ret;}void dfs(int u){    vis[u]=true;    for(int p=first[u];p;p=nxt[p])        if(wide[p]&&vis[goal[p]]==false)            dfs(goal[p]);    return ;}void mergesort(int l,int r){    if(l==r) return ;    for(int i=2;i<=tot;i+=2)        wide[i]=wide[i^1]=(wide[i]+wide[i^1])>>1;    S=id[l];T=id[r];    tmpflow=solve();    memset(vis,false,sizeof(vis));    dfs(S);    for(int i=1;i<=n;++i)        if(vis[i])            for(int j=1;j<=n;++j)                if(!vis[j])                    flowsze[i][j]=flowsze[j][i]=min(tmpflow,flowsze[i][j]);    int lef=l,righ=r;    for(int i=l;i<=r;++i)        if(vis[id[i]])            tmp[lef++]=id[i];        else            tmp[righ--]=id[i];    for(int i=l;i<=r;++i)        id[i]=tmp[i];    if(lef!=l)        mergesort(l,lef-1);    if(righ!=r)        mergesort(righ+1,r);    return ;}signed main(){    int t=read();    while(t--){        n=read();m=read();tot=1;        memset(first,0,sizeof(first));        memset(flowsze,127,sizeof(flowsze));        for(int i=1;i<=n;++i)            id[i]=i;        for(int i=1;i<=m;++i){            a=read();b=read();c=read();            addedge(a,b,c);        }        mergesort(1,n);        q=read();        for(int i=1;i<=q;++i){            tmpflow=read();ans=0;            for(int j=1;j<n;++j)                for(int k=j+1;k<=n;++k)                    if(flowsze[j][k]<=tmpflow) ++ans;            write(ans);puts("");        }        puts("");    }    return 0;}

(2)不同的最小割(cqoi2016)
求有多少种数值不同的最小割

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<string>#include<ctime>#include<cmath>#include<algorithm>#include<cctype>#include<iomanip>#include<queue>using namespace std;inline int read(){    int i=0,f=1;    char ch;    for(ch=getchar();!isdigit(ch);ch=getchar())        if(ch=='-') f=-1;    for(;isdigit(ch);ch=getchar())        i=(i<<3)+(i<<1)+(ch^48);    return i*f;}int buf[1024];inline void write(int x){    if(!x){putchar('0');return ;}    if(x<0){putchar('-');x=-x;}    while(x){buf[++buf[0]]=x%10,x/=10;}    while(buf[0]) putchar(buf[buf[0]--]+48);    return ;}#define stan 1111#define sten 22222int tot,first[stan],nxt[sten],goal[sten],wide[sten];int tmp[stan],id[stan],flowsze[stan][stan],ans,n,m,q,tmpflow,a,b,c;int S,T,level[stan],line[stan*stan],cnt;bool vis[stan];queue<int>que;void addedge(int a,int b,int c){    nxt[++tot]=first[a];first[a]=tot;goal[tot]=b;wide[tot]=c;    nxt[++tot]=first[b];first[b]=tot;goal[tot]=a;wide[tot]=c;    return ;}bool bfs(){    while(!que.empty()) que.pop();    for(int i=1;i<=n;++i)        level[i]=-1;    level[S]=0;que.push(S);     while(!que.empty()){        int u=que.front();que.pop();        for(int p=first[u];p;p=nxt[p])            if(wide[p]&&level[goal[p]]==-1){                level[goal[p]]=level[u]+1;                if(goal[p]==T) return true;                que.push(goal[p]);             }    }    return false;}int dfs(int u,int flow){    if(u==T) return flow;    int ret=0,data;    for(int p=first[u];p;p=nxt[p])        if(wide[p]&&level[goal[p]]==level[u]+1){            data=dfs(goal[p],min(flow-ret,wide[p]));            if(data){                wide[p]-=data;                wide[p^1]+=data;                ret+=data;                if(ret==flow) return ret;             }        }    level[u]=-1;    return ret;}int solve(){    int ret=0;    while(bfs())        ret+=dfs(S,999999999);    return ret;}void dfs(int u){    vis[u]=true;    for(int p=first[u];p;p=nxt[p])        if(wide[p]&&vis[goal[p]]==false)            dfs(goal[p]);    return ;}void mergesort(int l,int r){    if(l==r) return ;    for(int i=2;i<=tot;i+=2)        wide[i]=wide[i^1]=(wide[i]+wide[i^1])>>1;    S=id[l];T=id[r];     tmpflow=solve();    memset(vis,false,sizeof(vis));    dfs(S);    for(int i=1;i<=n;++i)        if(vis[i])            for(int j=1;j<=n;++j)                if(!vis[j])                    flowsze[i][j]=flowsze[j][i]=min(tmpflow,flowsze[i][j]);    int lef=l,righ=r;    for(int i=l;i<=r;++i)        if(vis[id[i]])            tmp[lef++]=id[i];        else            tmp[righ--]=id[i];    for(int i=l;i<=r;++i)        id[i]=tmp[i];    if(lef!=l)        mergesort(l,lef-1);    if(righ!=r)        mergesort(righ+1,r);}signed main(){    n=read();m=read();tot=1;    memset(flowsze,127,sizeof(flowsze));    for(int i=1;i<=n;++i)        id[i]=i;    for(int i=1;i<=m;++i){        a=read();b=read();c=read();        addedge(a,b,c);    }    mergesort(1,n);    for(int i=1;i<n;++i)        for(int j=i+1;j<=n;++j)            line[++cnt]=flowsze[i][j];    sort(line+1,line+cnt+1);    for(int i=1;i<=cnt;++i)        if(line[i]!=line[i-1]) ++ans;    write(ans);    return 0;}

(3)juice junction(bzoj4435)
n个点两两之间最小割之和
你需要蛤希优化一下

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<string>#include<ctime>#include<cmath>#include<algorithm>#include<cctype>#include<iomanip>#include<queue>using namespace std;inline int read(){    int i=0,f=1;    char ch;    for(ch=getchar();!isdigit(ch);ch=getchar())        if(ch=='-') f=-1;    for(;isdigit(ch);ch=getchar())        i=(i<<3)+(i<<1)+(ch^48);    return i*f;}int buf[1024];inline void write(int x){    if(!x){putchar('0');return ;}    if(x<0){putchar('-');x=-x;}    while(x){buf[++buf[0]]=x%10,x/=10;}    while(buf[0]) putchar(buf[buf[0]--]+48);    return ;}#define stan 3333#define sten 11111int tot,first[stan],nxt[sten],goal[sten],wide[sten];int tmp[stan],id[stan],ans,n,m,q,tmpflow,a,b,c,pre[stan],edg[stan];int S,T,level[stan],ret;unsigned long long hash[4][stan],base;bool vis[stan];queue<int>que;void addedge(int a,int b,int c){    nxt[++tot]=first[a];first[a]=tot;goal[tot]=b;wide[tot]=c;    nxt[++tot]=first[b];first[b]=tot;goal[tot]=a;wide[tot]=c;    return ;}bool bfs(){    while(!que.empty()) que.pop();    for(int i=1;i<=n;++i)        level[i]=-1;    level[S]=0;que.push(S);     while(!que.empty()&&level[T]==-1){        int u=que.front();que.pop();        for(int p=first[u];p;p=nxt[p])            if(wide[p]&&level[goal[p]]==-1){                level[goal[p]]=level[u]+1;                pre[goal[p]]=u;                edg[goal[p]]=p;                if(goal[p]==T) break;                que.push(goal[p]);             }    }    if(level[T]!=-1){        ++ret;        for(int u=T;u!=S;u=pre[u]){            --wide[edg[u]];            ++wide[edg[u]^1];        }    }    return level[T]!=-1;}int solve(){    ret=0;    while(bfs());    return ret;}inline void dfs(int u){    vis[u]=true;    for(int p=first[u];p;p=nxt[p])        if(wide[p]&&vis[goal[p]]==false)            dfs(goal[p]);    return ;}void mergesort(int l,int r){    if(l==r) return ;    for(int i=2;i<=tot;i+=2)        wide[i]=wide[i^1]=(wide[i]+wide[i^1])>>1;    S=id[l];T=id[r];    tmpflow=solve();    memset(vis,false,sizeof(vis));    dfs(S);    base*=131;    for(int i=1;i<=n;++i)        if(~level[i])            hash[tmpflow][i]+=base;    int lef=l,righ=r;    for(int i=l;i<=r;++i)        if(vis[id[i]])            tmp[lef++]=id[i];        else            tmp[righ--]=id[i];    for(int i=l;i<=r;++i)        id[i]=tmp[i];    if(lef!=l)        mergesort(l,lef-1);    if(righ!=r)        mergesort(righ+1,r);    return ;}signed main(){    n=read();m=read();tot=1;base=1;    for(int i=1;i<=n;++i)         id[i]=i;    for(int i=1;i<=m;++i){        a=read();b=read();        addedge(a,b,1);    }    mergesort(1,n);    for(int i=1;i<n;++i)        for(int j=i+1;j<=n;++j)            for(int k=0;k<=3;++k)                if(hash[k][i]!=hash[k][j]){                    ans+=k;                    break;                }    write(ans);    return 0;}
原创粉丝点击