• 网络流套路小结


    讲课的时候发现自己好像网络流好像还行。。。

    但是建模套路还是很多 我这种脑子是不可能记住的 所以写一个总结吧

    需要掌握/实现/没写过的标出来了

    最小割建模:

    最大权闭合子图 CEOI order 线性代数

    最大密度子图

    文理分科模型(解方程法) BZOJ2132 

    距离限制模型 切糕

    平面图最小割转对偶图最短路 狼抓兔子 海拔

    01变量建模 COCONUTS

    最小割树(Gomory_Hu树)ZJOI2011最小割

    杂题 CC RIN SRM577 BoardPainting SRM558 SurroundingGame

    最大流/费用流建模:

    环覆盖

    HALL定理  CF 103E

    不等式差分模型 志愿者招募 Delight For A Cat

    上下界网络流 (见liu_runda博客)BZOJ 3698 营救皮卡丘

    数据结构优化建图 BZOJ3218

    杂 CF 510E 星际穿越 WC 剪刀石头布 BRIDGES(带权混合图欧拉回路) CC GNUM SRM594 FoxAndGo3 SRM627 LaserTowers 美食节 SRM590 FoxAndCity

    然后就发现没写的太多了 不标了

    一共是24道题 目前来说没有时间做 网络流按照一天4道的话是一周时间 大概在培训结束先开网络流吧


    开始填坑了...QAQ

     bzoj3996 TJOI2015 线性代数

    想了一下想到了Coconuts那个题,然后发现还不是很会统计...
    研究了一下洛谷的第一篇题解...发现是神仙的解方程法...学习到了...
    就是肯定是最小割建图,考虑建Coconuts那个题的边,然后通过解方程就可以分配每条边了。具体可以参考TA的题解...
    后来发现...特么建N*N个点也都能过...我太难了...
    //Love and Freedom.
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #define ll long long
    #define inf 20021225
    #define N 501
    using namespace std;
    int read()
    {
        int s=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
        while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
        return f*s;
    }
    struct edge{int to,lt,f;}e[N*N*20];
    queue<int> q; int dep[N*4],cnt=1,in[N*4],s,t;
    int a[N][N],c[N];
    void add(int x,int y,int f)
    {
        e[++cnt].to=y; e[cnt].lt=in[x]; e[cnt].f=f; in[x]=cnt;
        e[++cnt].to=x; e[cnt].lt=in[y]; e[cnt].f=0; in[y]=cnt;
    }
    bool bfs()
    {
        while(!q.empty())    q.pop();
        memset(dep,0,sizeof(dep));
        q.push(s); dep[s]=1;
        while(!q.empty())
        {
            int x=q.front(); q.pop();
            for(int i=in[x];i;i=e[i].lt)
                if(e[i].f&&!dep[e[i].to])
                {
                    q.push(e[i].to),dep[e[i].to]=dep[x]+1;
                    if(e[i].to==t)    return 1;
                }
        }
        return 0;
    }
    int dfs(int x,int flow)
    {
        if(x==t)    return flow;
        int cur=flow;
        for(int i=in[x];i;i=e[i].lt)
            if(e[i].f&&dep[e[i].to]==dep[x]+1)
            {
                int tmp=dfs(e[i].to,min(e[i].f,cur));
                e[i].f-=tmp; e[i^1].f+=tmp; cur-=tmp;
                if(!cur)    return flow;
            }
        dep[x]=-1; return flow-cur;
    }
    int dinic()
    {
        int ans=0;
        while(bfs())    ans+=dfs(s,inf);
        return ans;
    }
    int main()
    {
        int n=read(),ful=0;
        for(int i=1;i<=n;i++)    for(int j=1;j<=n;j++)
            a[i][j]=read(),ful+=a[i][j];
        for(int i=1;i<=n;i++)    c[i]=read();
        s=N*4-3; t=s+1;
        for(int i=1;i<=n;i++)
        {
            int ans=0;
            for(int j=1;j<=n;j++)
            {
                if(i!=j)    add(i,j,a[i][j]+a[j][i]);
                ans+=a[i][j]+a[j][i];
            }    
            add(s,i,ans); add(i,t,c[i]<<1);
        }
        printf("%d
    ",ful-(dinic()>>1));
        return 0;
    }
    View Code

    bzoj3144 HNOI2013 切糕

    经典的距离限制最小割模型 比较有趣。
    (x,d)->(y,d-k) (y,d)->(x,d-k) inf
    可以限制两个点之间距离不超过k
    //Love and Freedom.
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #define ll long long
    #define inf 20021225
    #define N 200010
    using namespace std;
    int read()
    {
        int s=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
        while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
        return f*s;
    }
    struct edge{int to,lt,f;}e[N*40];
    queue<int> que; int dep[N],cnt=1,in[N],s,t;
    void add(int x,int y,int f)
    {
        e[++cnt].to=y; e[cnt].lt=in[x]; e[cnt].f=f; in[x]=cnt;
        e[++cnt].to=x; e[cnt].lt=in[y]; e[cnt].f=0; in[y]=cnt;
    }
    bool bfs()
    {
        while(!que.empty())    que.pop();
        memset(dep,0,sizeof(dep));
        que.push(s); dep[s]=1;
        while(!que.empty())
        {
            int x=que.front(); que.pop();
            for(int i=in[x];i;i=e[i].lt)
                if(e[i].f&&!dep[e[i].to])
                {
                    que.push(e[i].to),dep[e[i].to]=dep[x]+1;
                    if(e[i].to==t)    return 1;
                }
        }
        return 0;
    }
    int dfs(int x,int flow)
    {
        if(x==t)    return flow;
        int cur=flow;
        for(int i=in[x];i;i=e[i].lt)
            if(e[i].f&&dep[e[i].to]==dep[x]+1)
            {
                int tmp=dfs(e[i].to,min(e[i].f,cur));
                e[i].f-=tmp; e[i^1].f+=tmp; cur-=tmp;
                if(!cur)    return flow;
            }
        dep[x]=-1; return flow-cur;
    }
    int dinic()
    {
        int ans=0;
        while(bfs())    ans+=dfs(s,inf);
        return ans;
    }
    int a[41][41][41],p,q,r,d,dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
    int id(int x,int y,int d)
    {
        if(!d)    return s;
        return (d-1)*p*q+(x-1)*q+y;
    }
    int main()
    {
        s=N-3; t=s+1;
        p=read(),q=read(),r=read(),d=read();
        for(int i=1;i<=r;i++)    for(int j=1;j<=p;j++)
            for(int k=1;k<=q;k++)    a[j][k][i]=read();
        for(int i=1;i<=p;i++)    for(int j=1;j<=q;j++)
        {
            for(int k=1;k<=r;k++)
                add(id(i,j,k-1),id(i,j,k),a[i][j][k]);
            add(id(i,j,r),t,inf);
        }
        for(int i=1;i<=p;i++)    for(int j=1;j<=q;j++)
            for(int w=0;w<4;w++)
            {
                int x=dx[w]+i,y=dy[w]+j;
                if(!x||!y||x>p||y>q)    continue;
                for(int k=d+1;k<=r;k++)    add(id(i,j,k),id(x,y,k-d),inf);
            }
        printf("%d
    ",dinic());
        return 0;
    }
    View Code

    bzoj2229 ZJOI2011 最小割

    最小割树!板子题不说了qwq
    //Love and Freedom.
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<vector>
    #include<queue>
    #define ll long long
    #define inf 2002122500
    #define M 12010
    #define N 401
    #define pa pair<int,int>
    #define mp make_pair
    #define fs first
    #define se second
    #define pb push_back
    using namespace std;
    int read()
    {
        int s=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
        while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
        return f*s;
    }
    struct edge{int to,lt,f;}e[M]; int ful[M];
    int in[N],cnt; vector<pa> tr[N];
    void init(int n)
    {
        memset(in,0,sizeof(in)); cnt=1;
        for(int i=1;i<=n;i++)    tr[i].clear();
    }
    void add(int x,int y,int f)
    {
        e[++cnt].to=y; e[cnt].lt=in[x]; e[cnt].f=f; in[x]=cnt; ful[cnt]=f;
        e[++cnt].to=x; e[cnt].lt=in[y]; e[cnt].f=f; in[y]=cnt; ful[cnt]=f;
    }
    void link(int x,int y,int f)
    {
        tr[x].pb(mp(y,f)); tr[y].pb(mp(x,f));
    }
    queue<int> q; int dep[N];
    bool bfs(int s,int t)
    {
        while(!q.empty())    q.pop();
        memset(dep,0,sizeof(dep));
        q.push(s); dep[s]=1;
        while(!q.empty())
        {
            int x=q.front(); q.pop();
            for(int i=in[x];i;i=e[i].lt)
                if(!dep[e[i].to]&&e[i].f)
                {
                    q.push(e[i].to); dep[e[i].to]=dep[x]+1;
                    if(e[i].to==t)    return 1;
                }
        }
        return 0;
    }
    int dfs(int t,int x,int flow)
    {
        if(x==t)    return flow;
        int cur=flow;
        for(int i=in[x];i;i=e[i].lt)
            if(e[i].f&&dep[e[i].to]==dep[x]+1)
            {
                int tmp=dfs(t,e[i].to,min(cur,e[i].f));
                e[i].f-=tmp; e[i^1].f+=tmp; cur-=tmp;
                if(!cur)    return flow;
            }
        dep[x]=-1; return flow-cur;
    }
    void dinic(int s,int t)
    {
        int ans=0;
        for(int i=2;i<=cnt;i++)    e[i].f=ful[i];
        while(bfs(s,t))    ans+=dfs(t,s,inf);
        link(s,t,ans);// printf("%d %d %d
    ",s,t,ans);
    }
    int id[N],ss[N],tt[N];
    void build(int *a,int n)
    {
        if(n<2)    return;
        dinic(a[0],a[1]); int tops=0,topt=0;
        for(int i=0;i<n;i++)
            if(dep[a[i]])    ss[tops++]=a[i];
            else    tt[topt++]=a[i];
        memcpy(a,ss,tops<<2); memcpy(a+tops,tt,topt<<2);
        build(a,tops); build(a+tops,topt);
    }
    vector<int> ans;
    void dfs2(int x,int f,int v)
    {
        for(int i=0;i<tr[x].size();i++)
        {
            pa tmp=tr[x][i];
            int y=tmp.fs,val=min(v,tmp.se);
            if(y==f)    continue;
            ans.pb(val); dfs2(y,x,val);
        }
    }
    void calc(int n)
    {
        ans.clear();
        for(int i=1;i<=n;i++)
            dfs2(i,i,inf);
    }
    int main()
    {
        int T=read(),x,y,v;
        while(T--)
        {
            cnt=1; int n=read(),m=read();
            for(int i=1;i<=m;i++)    x=read(),y=read(),v=read(),add(x,y,v);    
            for(int i=0;i<n;i++)    id[i]=i+1;
            build(id,n); calc(n); sort(ans.begin(),ans.end());
            int Q=read();
            while(Q--)
            {
                x=read(); printf("%d
    ",(upper_bound(ans.begin(),ans.end(),x)-ans.begin())>>1);
            }
            init(n); puts("");
        }
        return 0;
    }
    View Code

     bzoj4519 CQOI2016 不同的最小割

    板子++
    //Love and Freedom.
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<vector>
    #include<queue>
    #define ll long long
    #define inf 2002122500
    #define M 20010
    #define N 1010
    #define pa pair<int,int>
    #define mp make_pair
    #define fs first
    #define se second
    #define pb push_back
    using namespace std;
    int read()
    {
        int s=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
        while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
        return f*s;
    }
    struct edge{int to,lt,f;}e[M]; int ful[M];
    int in[N],cnt; vector<int> len;
    void add(int x,int y,int f)
    {
        e[++cnt].to=y; e[cnt].lt=in[x]; e[cnt].f=f; in[x]=cnt; ful[cnt]=f;
        e[++cnt].to=x; e[cnt].lt=in[y]; e[cnt].f=f; in[y]=cnt; ful[cnt]=f;
    }
    queue<int> q; int dep[N];
    bool bfs(int s,int t)
    {
        while(!q.empty())    q.pop();
        memset(dep,0,sizeof(dep));
        q.push(s); dep[s]=1;
        while(!q.empty())
        {
            int x=q.front(); q.pop();
            for(int i=in[x];i;i=e[i].lt)
                if(!dep[e[i].to]&&e[i].f)
                {
                    q.push(e[i].to); dep[e[i].to]=dep[x]+1;
                    if(e[i].to==t)    return 1;
                }
        }
        return 0;
    }
    int dfs(int t,int x,int flow)
    {
        if(x==t)    return flow;
        int cur=flow;
        for(int i=in[x];i;i=e[i].lt)
            if(e[i].f&&dep[e[i].to]==dep[x]+1)
            {
                int tmp=dfs(t,e[i].to,min(cur,e[i].f));
                e[i].f-=tmp; e[i^1].f+=tmp; cur-=tmp;
                if(!cur)    return flow;
            }
        dep[x]=-1; return flow-cur;
    }
    void dinic(int s,int t)
    {
        int ans=0;
        for(int i=2;i<=cnt;i++)    e[i].f=ful[i];
        while(bfs(s,t))    ans+=dfs(t,s,inf);
        len.pb(ans);
    }
    int id[N],ss[N],tt[N];
    void build(int *a,int n)
    {
        if(n<2)    return;
        dinic(a[0],a[1]); int tops=0,topt=0;
        for(int i=0;i<n;i++)
            if(dep[a[i]])    ss[tops++]=a[i];
            else    tt[topt++]=a[i];
        memcpy(a,ss,tops<<2); memcpy(a+tops,tt,topt<<2);
        build(a,tops); build(a+tops,topt);
    }
    int main()
    {
        int x,y,v;
        cnt=1; int n=read(),m=read();
        for(int i=1;i<=m;i++)    x=read(),y=read(),v=read(),add(x,y,v);    
        for(int i=0;i<n;i++)    id[i]=i+1;
        build(id,n); sort(len.begin(),len.end());
        printf("%d
    ",unique(len.begin(),len.end())-len.begin());
        return 0;
    }
    View Code
    CF103E Buying Sets
    发现自己学的可能是假的最大权闭合子图???
    貌似合理的应该是当权>=0 是(s,i,a[i]) <0是(i,t,-a[i])然后需要割需要割掉的-正的所有。。。
    发现这个东西就是满足Hall定理,保证有匹配。其实就是集合对应的所有数必须要覆盖掉。。。所以就是最大权闭合子图模型了。。。
    //Love and Freedom.
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #define ll long long
    #define inf 2002122500
    #define N 310
    using namespace std;
    int read()
    {
        int s=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
        while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
        return f*s;
    }
    struct edge{int to,lt,f;}e[N*N*4];
    queue<int> que; int dep[N],cnt=1,in[N],s,t;
    void add(int x,int y,int f)
    {
        e[++cnt].to=y; e[cnt].lt=in[x]; e[cnt].f=f; in[x]=cnt;
        e[++cnt].to=x; e[cnt].lt=in[y]; e[cnt].f=0; in[y]=cnt;
    }
    bool bfs()
    {
        while(!que.empty())    que.pop();
        memset(dep,0,sizeof(dep));
        que.push(s); dep[s]=1;
        while(!que.empty())
        {
            int x=que.front(); que.pop();
            for(int i=in[x];i;i=e[i].lt)
                if(e[i].f&&!dep[e[i].to])
                {
                    que.push(e[i].to),dep[e[i].to]=dep[x]+1;
                    if(e[i].to==t)    return 1;
                }
        }
        return 0;
    }
    int dfs(int x,int flow)
    {
        if(x==t)    return flow;
        int cur=flow;
        for(int i=in[x];i;i=e[i].lt)
            if(e[i].f&&dep[e[i].to]==dep[x]+1)
            {
                int tmp=dfs(e[i].to,min(e[i].f,cur));
                e[i].f-=tmp; e[i^1].f+=tmp; cur-=tmp;
                if(!cur)    return flow;
            }
        dep[x]=-1; return flow-cur;
    }
    int dinic()
    {
        int ans=0;
        while(bfs())    ans+=dfs(s,inf);
        return ans;
    }
    int k[N],edg[N][N],p[N],a[N],n; bool vis[N];
    bool match(int x)
    {
        for(int i=1;i<=k[x];i++)
            if(!vis[edg[x][i]])
            {
                vis[edg[x][i]]=1;
                if(!p[edg[x][i]] || match(p[edg[x][i]]))
                    return p[edg[x][i]]=x,true;
            }
        return false;
    }
    void Match()
    {
        for(int i=1;i<=n;i++)
        {
            memset(vis,0,sizeof(vis));
            match(i);
        }
    }
    void build()
    {
        for(int i=1;i<=n;i++)    for(int j=1;j<=k[i];j++)
            if(p[edg[i][j]]!=i)    add(i,p[edg[i][j]],inf);
    }
    int main()
    {
        s=N-3; t=s+1; n=read();
        for(int i=1;i<=n;i++)
        {
            k[i]=read();
            for(int j=1;j<=k[i];j++)
                edg[i][j]=read();
        }
        int ful=0;
        for(int i=1;i<=n;i++)
        {
            a[i]=-read();
            if(a[i]>=0)    add(s,i,a[i]),ful+=a[i];
            else    add(i,t,-a[i]);
        }
        Match(); build();
        printf("%d
    ",dinic()-ful);
        return 0;
    }
    View Code

    bzoj4842 Delight For A Cat

    距离限制建模...今天有点咕,明天写完另一道一起总结吧...117组数据好毒啊..
    //Love and Freedom.
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #define ll long long
    #define inf 20021225
    #define N 2010
    using namespace std;
    int read()
    {
        int s=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
        while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
        return f*s;
    }
    struct edge{int to,lt,f,fr;ll c;}e[N*20];
    int in[N],cnt=1,from[N],a[N],b[N]; bool vis[N];
    void add(int x,int y,int f,ll c)
    {
        e[++cnt].to=y; e[cnt].lt=in[x]; in[x]=cnt; e[cnt].fr=x; e[cnt].f=f; e[cnt].c=c;
        e[++cnt].to=x; e[cnt].lt=in[y]; in[y]=cnt; e[cnt].fr=y; e[cnt].f=0; e[cnt].c=-c;
    }
    queue<int> q; ll dis[N]; int s,t;
    bool spfa()
    {
        memset(dis,63,sizeof(dis));
        dis[s]=0; q.push(s); vis[s]=1;
        while(!q.empty())
        {
            int x=q.front(); q.pop(); vis[x]=0;
            for(int i=in[x];i;i=e[i].lt)
            {
                int y=e[i].to;
                if(e[i].f&&dis[y]>dis[x]+e[i].c)
                {
                    dis[y]=dis[x]+e[i].c; from[y]=i;
                    if(!vis[y])    q.push(y),vis[y]=1;
                }
            }
        }
        return dis[t]<dis[0];
    }
    ll dinic()
    {
        ll ans=0;
        while(spfa())
        {
            int flow=inf;
            for(int i=from[t];i;i=from[e[i].fr])    flow=min(flow,e[i].f);
            for(int i=from[t];i;i=from[e[i].fr])
                ans+=flow*e[i].c,e[i].f-=flow,e[i^1].f+=flow;
            //printf("%d %lld
    ",flow,dis[t]);
        }
        return ans;
    }
    int id[N];
    int main()
    {
        int n=read(),k=read(),t1=read(),t2=read(); ll ans=0;
        s=N-3; t=s+1; int ss=t+1; add(s,ss,k-t1,0);
        for(int i=1;i<=k;i++)    add(ss,i,inf,0);
        for(int i=1;i<=n;i++)
        {
            a[i]=read(),ans+=a[i];
            add(i,i+1<=n?i+1:t,k-t1-t2,0);
        }
        for(int i=1;i<=n;i++)
        {
            b[i]=read();
            add(i,i+k<=n?i+k:t,1,a[i]-b[i]); id[i]=cnt;
        }
        printf("%lld
    ",ans-dinic());
        for(int i=1;i<=n;i++)
            if(e[id[i]].f)    printf("E");
            else    printf("S");
        printf("
    ");    
        return 0;
    }
    View Code

    bzoj2324 营救皮卡丘

    一种做法是建分层图然后跑上下界费用流 显然不是很好做
    另一种就是用k条路径覆盖所有点 其中两点距离需要特殊处理(只能走小的点) 这个的话类似于路径覆盖,不要刻意按照建图理解,按照“找出路”的思路理解比较方便。qwq。
    //Love and Freedom.
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #define ll long long
    #define inf 20021225
    #define N 420
    #define M 100001
    using namespace std;
    int read()
    {
        int s=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
        while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
        return f*s;
    }
    int d[N][N];
    struct edge{int fr,to,lt,f,c;}e[M<<1];
    int cnt=1,in[N],from[N],dis[N],s,t;
    queue<int> q; bool vis[N];
    void add(int x,int y,int f,int c)
    {
        e[++cnt].to=y; e[cnt].lt=in[x]; in[x]=cnt; e[cnt].f=f; e[cnt].c=c; e[cnt].fr=x;
        e[++cnt].to=x; e[cnt].lt=in[y]; in[y]=cnt; e[cnt].f=0; e[cnt].c=-c; e[cnt].fr=y;
    }
    bool spfa()
    {
        memset(dis,48,sizeof(dis));
        q.push(s); dis[s]=0; vis[s]=1;
        while(!q.empty())
        {
            int x=q.front(); q.pop(); vis[x]=0;
            for(int i=in[x];i;i=e[i].lt)
            {
                int y=e[i].to;
                if(e[i].f&&dis[y]>dis[x]+e[i].c)
                {
                    dis[y]=dis[x]+e[i].c; from[y]=i;
                    if(!vis[y])    vis[y]=1,q.push(y);
                }
            }
        }
        return dis[t]<dis[N-1];
    }
    int dinic()
    {
        int ans=0;
        while(spfa())
        {
            int flow=inf;
            for(int i=from[t];i;i=from[e[i].fr])    flow=min(flow,e[i].f);
            for(int i=from[t];i;i=from[e[i].fr])
                e[i].f-=flow,e[i^1].f+=flow,ans+=flow*e[i].c;
        }
        return ans;
    }
    int main()
    {
        int n=read(),m=read(),k=read();
        s=N-3; t=s+1; memset(d,48,sizeof(d));
        for(int i=1;i<=m;i++)
        {
            int a=read(),b=read(),l=read();
            d[a][b]=d[b][a]=min(d[a][b],l);
        }
        for(int i=0;i<=n;i++)    d[i][i]=0;
        for(int k=0;k<=n;k++)    for(int i=0;i<=n;i++)
            for(int j=0;j<=n;j++) if(k<=i||k<=j)
                d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
        add(s,0,k,0);
        for(int i=1;i<=n;i++)    add(s,i,1,0),add(i+n,t,1,0);
        for(int i=0;i<=n;i++)    for(int j=i+1;j<=n;j++)
            if(d[i][j]<d[N-1][N-1])    add(i,j+n,1,d[i][j]);
        printf("%d
    ",dinic());
        return 0;
    }
    View Code

    bzoj2597 WC2007 石头剪刀布

    计数题是怎么能想到网络流的啊喂。
    正难则反,我们考虑三元组不构成三元环的方式,只有一种就是一个点两个入度,一个点两个出度,一个一入一出。我们考虑统计出度的。
    构图比较显然,s向每个竞赛点连(1,0),竞赛点再向i,j分别连(1,0)。每个人再向t连边,但我们发现这个贡献是一个二次的柿子C(wi,2)=(wi-1)*wi/2,发现长的和高斯式一样,凸费用拆边就可以啦。
    最后要注意已经有了的需要单独统计。
    //Love and Freedom.
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #define ll long long
    #define inf 20021225
    #define N 220
    #define M 500001
    using namespace std;
    int read()
    {
        int s=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
        while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
        return f*s;
    }
    int d[N][N],tot;
    struct edge{int fr,to,lt,f,c;}e[M<<1];
    int cnt=1,in[N*N],from[N*N],dis[N*N],s,t;
    queue<int> q; bool vis[N*N];
    void add(int x,int y,int f,int c)
    {
        e[++cnt].to=y; e[cnt].lt=in[x]; in[x]=cnt; e[cnt].f=f; e[cnt].c=c; e[cnt].fr=x;
        e[++cnt].to=x; e[cnt].lt=in[y]; in[y]=cnt; e[cnt].f=0; e[cnt].c=-c; e[cnt].fr=y;
    }
    bool spfa()
    {
        memset(dis,48,sizeof(dis));
        q.push(s); dis[s]=0; vis[s]=1;
        while(!q.empty())
        {
            int x=q.front(); q.pop(); vis[x]=0;
            for(int i=in[x];i;i=e[i].lt)
            {
                int y=e[i].to;
                if(e[i].f&&dis[y]>dis[x]+e[i].c)
                {
                    dis[y]=dis[x]+e[i].c; from[y]=i;
                    if(!vis[y])    vis[y]=1,q.push(y);
                }
            }
        }
        return dis[t]<dis[0];
    }
    int dinic()
    {
        int ans=0;
        while(spfa())
        {
            int flow=inf;
            for(int i=from[t];i;i=from[e[i].fr])    flow=min(flow,e[i].f);
            for(int i=from[t];i;i=from[e[i].fr])
                e[i].f-=flow,e[i^1].f+=flow,ans+=flow*e[i].c;
        }
        return ans;
    }
    int w[N],id[N][N];
    int main()
    {
        //freopen("in.txt","r",stdin);
        //freopen("ans.txt","w",stdout);
        int n=read();
        s=N*N-3; t=s+1; tot=n; int ans=0;
        for(int i=1;i<=n;i++)    for(int j=1;j<=n;j++)
        {
            id[i][j]=read(); w[i]+=id[i][j]==1;
            if(id[i][j]==2 && i<j)    id[i][j]=++tot,add(tot,i,1,0),d[i][j]=cnt,add(tot,j,1,0),d[j][i]=cnt;
        }
        for(int i=n+1;i<=tot;i++)    add(s,i,1,0);
        for(int i=1;i<=n;i++)
        {
            ans+=w[i]*(w[i]-1)/2;
            for(int j=w[i];j<=n;j++)
                add(i,t,1,j);
        }
        printf("%d
    ",n*(n-1)*(n-2)/6-ans-dinic());
        for(int i=1;i<=n;i++,printf("
    "))    for(int j=1;j<=n;j++)
        {
            if(d[i][j])    printf("%d ",e[d[i][j]].f?1:0);
            else    printf("%d ",id[i][j]);
        }
        return 0;
    }
    View Code

    CF910E Fox And Dinner

    发现每个数>=2所以是二分图,环长度>=3就每个点找入点出点就可以了。
    //Love and Freedom.
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<vector>
    #include<queue>
    #define ll long long
    #define inf 2002122500
    #define M 100010
    #define N 410
    #define pb push_back
    using namespace std;
    int read()
    {
        int s=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
        while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
        return f*s;
    }
    struct edge{int to,lt,f;}e[M];
    int in[N],cnt=1,s,t,a[N];
    void add(int x,int y,int f)
    {
        e[++cnt].to=y; e[cnt].lt=in[x]; e[cnt].f=f; in[x]=cnt;
        e[++cnt].to=x; e[cnt].lt=in[y]; e[cnt].f=0; in[y]=cnt;
    }
    queue<int> q; int dep[N];
    bool bfs()
    {
        while(!q.empty())    q.pop();
        memset(dep,0,sizeof(dep));
        q.push(s); dep[s]=1;
        while(!q.empty())
        {
            int x=q.front(); q.pop();
            for(int i=in[x];i;i=e[i].lt)
                if(!dep[e[i].to]&&e[i].f)
                {
                    q.push(e[i].to); dep[e[i].to]=dep[x]+1;
                    if(e[i].to==t)    return 1;
                }
        }
        return 0;
    }
    int dfs(int x,int flow)
    {
        if(x==t)    return flow;
        int cur=flow;
        for(int i=in[x];i;i=e[i].lt)
            if(e[i].f&&dep[e[i].to]==dep[x]+1)
            {
                int tmp=dfs(e[i].to,min(cur,e[i].f));
                e[i].f-=tmp; e[i^1].f+=tmp; cur-=tmp;
                if(!cur)    return flow;
            }
        dep[x]=-1; return flow-cur;
    }
    int dinic()
    {
        int ans=0;
        while(bfs())    ans+=dfs(s,inf);
        //printf("%d
    ",ans);
        return ans;
    }
    bool isp(int x)
    {
        for(int i=2;i*i<=x;i++)    if(x%i==0)    return 0;
        return 1;
    }
    vector<int> ans[N]; bool vis[N];
    void go(int k,int x)
    {
        if(vis[x])    return;
        vis[x]=1; ans[k].pb(x);
        //printf("%d ",x);
        for(int i=in[x];i;i=e[i].lt)
        {
            if(e[i].to==s || e[i].to==t)    continue;
            //printf("*");
            //printf("%d %d %d
    ",x,e[i].to,e[i].f);
            if((a[x]&1) && !e[i].f)
                go(k,e[i].to);
            if((!(a[x]&1)) && e[i].f)
                go(k,e[i].to);
        }
    }
    int main()
    {
        int n=read(); s=N-3; t=s+1;
        for(int i=1;i<=n;i++)    a[i]=read();
        for(int i=1;i<=n;i++)
        {
            if(a[i]&1)    add(s,i,2);
            else    add(i,t,2);
        }
        for(int i=1;i<=n;i++)    if(a[i]&1)
        {
            for(int j=1;j<=n;j++)    if(isp(a[i]+a[j]))
                add(i,j,1);
        }
        if(dinic()<n)    printf("Impossible
    ");
        else
        {
            int fin=0;
            for(int i=1;i<=n;i++)    if(!vis[i])    go(++fin,i);
            printf("%d
    ",fin);
            for(int i=1;i<=fin;i++)
            {
                printf("%d ",ans[i].size());
                for(int j=0;j<ans[i].size();j++)
                    printf("%d ",ans[i][j]);
                printf("
    ");
            }
        }
        return 0;
    }
    View Code

    bzoj2879 美食节

    和SCOI2007修车是一道题,只不过数据范围扩大了。
    考虑暴力建图的话我们会有约6e6条边,显然没戏。
    但是我们只需要跑sigma(pi)次最小费用流,所以我们考虑动态开点。
    即每次找到增广路上的那个厨师,让它继续扩展一道菜,这样的话,我们的复杂度就是对的了。O(np^2lgN)。(SC选手nb啊
    //Love and Freedom.
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #define ll long long
    #define inf 20021225
    #define N 4200
    #define M 500001
    using namespace std;
    int read()
    {
        int s=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
        while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
        return f*s;
    }
    int d[N][N];
    struct edge{int fr,to,lt,f,c;}e[M<<1];
    int cnt=1,in[N],from[N],dis[N],s,t;
    queue<int> q; bool vis[N];
    void add(int x,int y,int f,int c)
    {
        e[++cnt].to=y; e[cnt].lt=in[x]; in[x]=cnt; e[cnt].f=f; e[cnt].c=c; e[cnt].fr=x;
        e[++cnt].to=x; e[cnt].lt=in[y]; in[y]=cnt; e[cnt].f=0; e[cnt].c=-c; e[cnt].fr=y;
    }
    bool spfa()
    {
        memset(dis,48,sizeof(dis));
        q.push(s); dis[s]=0; vis[s]=1;
        while(!q.empty())
        {
            int x=q.front(); q.pop(); vis[x]=0;
            for(int i=in[x];i;i=e[i].lt)
            {
                int y=e[i].to;
                if(e[i].f&&dis[y]>dis[x]+e[i].c)
                {
                    dis[y]=dis[x]+e[i].c; from[y]=i;
                    if(!vis[y])    vis[y]=1,q.push(y);
                }
            }
        }
        return dis[t]<dis[N-1];
    }
    int dinic()
    {
        int ans=0; int flow=inf;
        for(int i=from[t];i;i=from[e[i].fr])    flow=min(flow,e[i].f);
        for(int i=from[t];i;i=from[e[i].fr])
            e[i].f-=flow,e[i^1].f+=flow,ans+=flow*e[i].c;
        return ans;
    }
    int p[N],poi,w[N][N],ans,id[N];
    void upd()
    {
        ans+=dinic(); 
        int x=e[from[t]].fr; id[++poi]=id[x];
        add(poi,t,1,0);
        for(int i=in[x];i;i=e[i].lt)
        {
            int y=e[i].to,v=e[i^1].c;
            if(y==t)    continue; v+=w[y][id[x]];
            add(y,poi,1,v);
        }
    }
    int main()
    {
        int n=read(),m=read(); s=N-3; t=s+1;
        for(int i=1;i<=n;i++)
            p[i]=read(),add(s,i,p[i],0);
        poi=n+m;
        for(int i=1;i<=n;i++)    for(int j=1;j<=m;j++)
            w[i][j]=read(), add(i,n+j,1,w[i][j]);
        for(int i=1;i<=m;i++)    add(n+i,t,1,0),id[n+i]=i;
        while(spfa())    upd();
        printf("%d
    ",ans);
        return 0;
    }
    View Code

    bzoj3218 a+b problem

    终于把它写了...
    考虑建图,S->i b[i] i->T w[i] i->i' p[i] i'->j inf
    每次新建一条链来保证重复的不会冲突。
    就是基本的主席树优化建图吧...
    //Love and Freedom.
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #define ll long long
    #define inf 20021225
    #define N 500010
    #define ls(x) T[x].son[0]
    #define rs(x) T[x].son[1]
    using namespace std;
    int read()
    {
        int s=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
        while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
        return f*s;
    }
    struct edge{int to,lt,f;}e[N<<1];
    struct node{int son[2],l,r;}T[N];
    int in[N],cnt=1,poi,dep[N],s,t;
    queue<int> q;
    void add(int x,int y,int f)
    {
        e[++cnt].to=y; e[cnt].lt=in[x]; in[x]=cnt; e[cnt].f=f;
        e[++cnt].to=x; e[cnt].lt=in[y]; in[y]=cnt; e[cnt].f=0;
    }
    bool bfs()
    {
        while(!q.empty())    q.pop();
        memset(dep,0,sizeof(dep));
        q.push(s); dep[s]=1; 
        while(!q.empty())
        {
            int x=q.front(); q.pop();
            for(int i=in[x];i;i=e[i].lt)
            {
                int y=e[i].to;
                if(!dep[y]&&e[i].f)
                {
                    dep[y]=dep[x]+1,q.push(y);
                    if(y==t)    return 1;
                }
            }
        }
        return 0;
    }
    int dfs(int x,int flow)
    {
        if(x==t)    return flow;
        int cur=flow;
        for(int i=in[x];i;i=e[i].lt)
            if(dep[e[i].to]==dep[x]+1&&e[i].f)
            {
                int tmp=dfs(e[i].to,min(e[i].f,cur));
                e[i].f-=tmp; e[i^1].f+=tmp; cur-=tmp;
                if(!cur)    return flow;
            }
        dep[x]=-1; return flow-cur;
    }
    int dinic()
    {
        int ans=0;
        while(bfs())    ans+=dfs(s,inf);
        return ans;
    }
    void query(int x,int l,int r,int LL,int RR,int fr)
    {
        if(LL<=l&&RR>=r){add(fr,x,inf); return;}
        int mid=l+r>>1;
        if(LL<=mid)    query(ls(x),l,mid,LL,RR,fr);
        if(RR>mid)    query(rs(x),mid+1,r,LL,RR,fr);
    }
    void modify(int &x,int l,int r,int p,int to)
    {
        T[++poi]=T[x]; add(poi,x,inf); x=poi; add(x,to,inf);
        if(l==r)    return; int mid=l+r>>1;
        if(p<=mid)    modify(ls(x),l,mid,p,to);
        else    modify(rs(x),mid+1,r,p,to);
    }
    int val[N],tot,n,a[N],b[N],l[N],r[N],w[N],p[N];
    int main()
    {
        n=read(); s=N-2; t=s+1; poi=n*2; int ans=0;
        for(int i=1;i<=n;i++)
        {
            a[i]=read(),b[i]=read(),w[i]=read(),l[i]=read(),r[i]=read(),p[i]=read();
            add(i,n+i,p[i]); add(s,i,b[i]); add(i,t,w[i]);
            val[++tot]=a[i]; val[++tot]=l[i]; val[++tot]=r[i];
            ans+=b[i]+w[i];
        }
        sort(val+1,val+tot+1); tot=unique(val+1,val+tot+1)-val-1;
        int rt=0;
        for(int i=1;i<=n;i++)
        {
            a[i]=lower_bound(val+1,val+tot+1,a[i])-val;
            l[i]=lower_bound(val+1,val+tot+1,l[i])-val;
            r[i]=lower_bound(val+1,val+tot+1,r[i])-val;
            query(rt,1,tot,l[i],r[i],i+n);
            modify(rt,1,tot,a[i],i);
        }
        printf("%d
    ",ans-dinic());
        return 0;
    }
    View Code

    做网络流也发现自己没有脑子...

  • 相关阅读:
    javascript 读取内联之外的样式(style、currentStyle、getComputedStyle区别介绍) (转载)
    JS笔记2 --定义对象
    JS笔记1
    Chrome 中的 JavaScript 断点设置和调试技巧 (转载)
    屏蔽移动端浏览器的长按事件
    移除IOS下按钮的原生样式
    HTML5中的Range对象的研究(转载)
    js中的 window.location、document.location、document.URL 对像的区别(转载)
    html中插入flash代码详解(转载)
    关于获取各种浏览器可见窗口大小(转载)
  • 原文地址:https://www.cnblogs.com/hanyuweining/p/11274961.html
Copyright © 2020-2023  润新知