• 不同的最小割(cqoi2016,bzoj4519)(最小割树)


    学过图论的同学都知道最小割的概念:对于一个图,某个对图中结点的划分将图中所有结点分成
    两个部分,如果结点(s,t)不在同一个部分中,则称这个划分是关于(s,t)的割。对于带权图来说,将
    所有顶点处在不同部分的边的权值相加所得到的值定义为这个割的容量,而(s,t)的最小割指的是在
    关于(s,t)的割中容量最小的割。
    而对冲刺(NOI)竞赛的选手而言,求带权图中两点的最小割已经不是什么难事了。我们可以把
    视野放宽,考虑有(N)个点的无向连通图中所有点对的最小割的容量,共能得到(frac{N(N−1)}{2})个数值。
    这些数值中互不相同的有多少个呢?这似乎是个有趣的问题。

    Input

    输入文件第一行包含两个数(N)(M),表示点数和边数。接下来M行,每行三个数(u,v,w)
    表示点(u)和点(v)(从1开始标号)之间有条边权值是(w)(1<=N<=850,1<=M<=8500,1<=W<=100000)

    Output

    输出文件第一行为一个整数,表示个数。

    Sample Input

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

    Sample Output

    3
    

    题意:

    中文题面,不解释

    题解:

    最小割树统计出所有最小割,然后计数就行了

    #include<bits/stdc++.h>
    #define re register 
    using namespace std;
    const int inf=1<<29,N=1010,M=20010;
    int n,m,a[N];
    int ans[N][N];
    int head[N],nxt[M],bian[M],zhi[M],tot;
    map<int,int>mp;
    void init(){
        tot=1;
        memset(head,0,sizeof head);
    }
    void add(int x,int y,int z){
        tot++;bian[tot]=y;zhi[tot]=z;nxt[tot]=head[x];head[x]=tot;
        tot++;bian[tot]=x;zhi[tot]=z;nxt[tot]=head[y];head[y]=tot;
    }
    void build(int m){
        for(int i=1;i<=m;i++){
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z);
        }
    }
    void rebuild(){
        for(int i=1;i<=tot;i+=2){
            zhi[i]=zhi[i^1]=(zhi[i]+zhi[i^1])/2;
        }
    }
    int v[N];
    void cut(int x){
        v[x]=1;
        for(int i=head[x];i;i=nxt[i]){
            if(zhi[i]&&!v[bian[i]])cut(bian[i]);
        }
    }
    int d[N];
    queue<int>q;
    bool bfs(int b,int e){
        memset(d,0,sizeof(d));
        while(!q.empty())q.pop();
        q.push(b);d[b]=1;
        while(!q.empty()){
            int x=q.front();q.pop();
            for(int i=head[x];i;i=nxt[i]){
                if(zhi[i] && !d[bian[i]]){
                    q.push(bian[i]);
                    d[bian[i]]=d[x]+1;
                    if(bian[i]==e)return 1;
                }
            }
        }
        return 0;
    }
    int dinic(int b,int e,int x,int flow){
        if(x==e)return flow;
        int rest=flow,k;
        for(int i=head[x];i && rest;i=nxt[i]){
            if(zhi[i] && d[bian[i]]==d[x]+1){
                k=dinic(b,e,bian[i],min(rest,zhi[i]));
                if(!k)d[bian[i]]=0;
                zhi[i]-=k;
                zhi[i^1]+=k;
                rest-=k;
            }
        }
        return flow-rest;
    }
    inline int maxflow(int b,int e){
        int flow=0,maxflow=0;
        while(bfs(b,e)){
            while(flow=dinic(b,e,b,inf))maxflow+=flow;
        }
        return maxflow;
    }
    int b,e;
    void solve(int l,int r){
        if(l==r)return;
        rebuild();
        b=a[l],e=a[r];
        re int mincut=maxflow(b,e);
        mp[mincut]=1;
        memset(v,0,sizeof v);
        cut(b);
        re int cnt=l-1;
        static int ls[N];
        for(re int i=l;i<=r;++i){
            if(v[a[i]]){
                ls[++cnt]=a[i];
            }
        }
        re int fj=cnt;
        for(re int i=l;i<=r;++i){
            if(!v[a[i]]){
                ls[++cnt]=a[i];
            }
        }
        for(re int i=l;i<=r;++i)a[i]=ls[i];
        solve(l,fj);
        solve(fj+1,r);
    }
    int main()
    {
        int b,e,q;
        memset(ans,0x3f,sizeof ans);
        cin>>n>>m;
        init();
        build(m);
        for(int i=1;i<=n;++i){
            a[i]=i;
        }
        solve(1,n);
        map<int,int>::iterator it;
        int ans=0;
        for(it=mp.begin();it!=mp.end();++it){
            ans++;
        }
        cout<<ans<<endl;
    }
    ?
    
  • 相关阅读:
    (3.4)常用知识-char与varchar的选择
    (3.3)常用知识-索引使用、维护与填充因子
    (3.2)常用知识-字符串处理
    (3.1)常用知识-日期处理
    基于Sql Server 2008的分布式数据库的实践
    将expression转化为数据类型int时发生算术溢出错误
    webserver and application server
    web前端
    linkin
    jquery load
  • 原文地址:https://www.cnblogs.com/zhenglier/p/10115913.html
走看看 - 开发者的网上家园