zoukankan      html  css  js  c++  java
  • 不同的最小割(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;
    }
    ?
    
  • 相关阅读:
    [开源项目]蓝点无限TWR算法-多基站多标签固件
    [开源项目] 蓝点无限 UWB Python版本上位机
    记一次RabbitMQ的脑裂(网络分区)问题
    使用Docker持久化部署SQL Server
    .NET---Exceptionless 轻量级的分布式日志管理平台
    python性能测试工具locust
    Javascript —— 线转树 or 树转线
    记录一个生僻知识点 —— JS字符模板替换
    车证识别工具|行驶证识别工具|行驶证识别OCR工具免费版V3.0.0.0
    C# CAD 凹凸点识别最大轮廓
  • 原文地址:https://www.cnblogs.com/zhenglier/p/10115913.html
Copyright © 2011-2022 走看看