zoukankan      html  css  js  c++  java
  • LibreOJ2042

    Portal

    Description

    给出一个给出一个(n(nleq850))个点(m(mleq8500))条边的无向图。定义(cut(s,t))等于(s,t)的最小割的容量,求在所有(cut(s,t))中不同的值有多少个。

    Solution

    有一个我也想不好为什么的性质:若(s,t)的最小割将原图划分成(S,T)两个集合,那么(forall uin S,vin T),有(cut(u,v)=cut(s,t))。那么我们可以用分治来做。
    对于一个点集(V),随便选择两个不同的点(s,t)并求出最小割和集合(S,T)。接下来只要分别考虑(S)内部的最小割和(T)内部的最小割即可。
    我们可以用一个数组(seq)上的一个区间([L,R])来代表集合。每次求出(S,T)后将(seq[L..R])(S)在前(T)在后的顺序重排,这样(S)(T)也可以用序列上的区间表示了。

    Code

    //「CQOI2016」不同的最小割
    #include <bits/stdc++.h>
    using namespace std;
    inline char gc()
    {
        static char now[1<<16],*s,*t;
        if(s==t) {t=(s=now)+fread(now,1,1<<16,stdin); if(s==t) return EOF;}
        return *s++;
    }
    inline int read()
    {
        int x=0; char ch=gc();
        while(ch<'0'||'9'<ch) ch=gc();
        while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=gc();
        return x;
    }
    const int N=1e3;
    const int INF=0x3F3F3F3F;
    int n,m;
    int edCnt,h[N];
    struct edge{int v,c,nxt;} ed[20*N];
    int s,t;
    void edAdd(int u,int v,int c)
    {
        edCnt++; ed[edCnt].v=v,ed[edCnt].c=c,ed[edCnt].nxt=h[u],h[u]=edCnt;
        edCnt++; ed[edCnt].v=u,ed[edCnt].c=c,ed[edCnt].nxt=h[v],h[v]=edCnt;
    }
    int dpt[N]; int op,cl,Q[N];
    bool bfs()
    {
        memset(dpt,0,sizeof dpt);
        op=cl=0; dpt[s]=1,Q[++cl]=s;
        while(op<cl)
        {
            int u=Q[++op]; if(u==t) break;
            for(int i=h[u];i;i=ed[i].nxt)
            {
                int v=ed[i].v;
                if(!dpt[v]&&ed[i].c) dpt[v]=dpt[u]+1,Q[++cl]=v;
            }
        }
        return dpt[t];
    }
    int fill(int u,int in)
    {
        if(u==t||in==0) return in;
        int out=0;
        for(int i=h[u];i;i=ed[i].nxt)
        {
            int v=ed[i].v,c=ed[i].c;
            if(!c||dpt[v]!=dpt[u]+1) continue;
            int fl=fill(v,min(in-out,c));
            if(fl==0) dpt[v]=0;
            else ed[i].c-=fl,ed[i^1].c+=fl,out+=fl;
            if(in==out) break;
        }
        return out;
    }
    int Dinic()
    {
        for(int i=2;i<=edCnt;i+=2) ed[i].c=ed[i^1].c=(ed[i].c+ed[i^1].c)>>1;
        int r=0;
        while(bfs()) r+=fill(s,INF);
        return r;
    }
    int cnt,seq[N],tmp[N];
    int ansCnt,ans[N];
    void solve(int L,int R)
    {
        if(L==R) return;
        s=seq[L+R>>1],t=seq[R]; ans[++ansCnt]=Dinic();
        int op=L-1,cl=R+1;
        for(int i=L;i<=R;i++) tmp[dpt[seq[i]]?++op:--cl]=seq[i];
        for(int i=L;i<=R;i++) seq[i]=tmp[i];
        solve(L,op),solve(cl,R);
    }
    int main()
    {
        n=read(),m=read();
        edCnt=1;
        for(int i=1;i<=m;i++)
        {
            int u=read(),v=read(),w=read();
            edAdd(u,v,w);
        }
        for(int i=1;i<=n;i++) seq[i]=i;
        solve(1,n);
        sort(ans+1,ans+ansCnt+1);
        printf("%d
    ",unique(ans+1,ans+ansCnt+1)-ans-1);
        return 0;
    }
    
  • 相关阅读:
    课程设计第十九天
    课程设计第十天八
    课程设计第十七天
    程序设计第十六天
    课程设计第十五天
    一个完整的大作业
    数据结构化与保存
    爬取新闻列表
    用requests库和BeautifulSoup4库爬取新闻列表
    中文词频统计及词云制作
  • 原文地址:https://www.cnblogs.com/VisJiao/p/LOJ2042.html
Copyright © 2011-2022 走看看