2017 暑假艾教集训 day12 网络流(最大流 最小割)!

来源:互联网 发布:入住淘宝达人 编辑:程序博客网 时间:2024/06/16 06:49

模板

using namespace std;int n,m;const int maxn=1005;struct node{    int to,next,cap;}edge[maxn<<2];int head[maxn],cnt;void add(int u,int v,int w){    edge[cnt].to=v; edge[cnt].next=head[u];    edge[cnt].cap=w;  head[u]=cnt++;}int deep[maxn];int bfs(int s,int t){    memset(deep,-1,sizeof(deep));    deep[s]=0;    queue<int> que;    que.push(s);    while(!que.empty())    {        int u=que.front(); que.pop();        for(int i=head[u];i!=-1;i=edge[i].next)        {            int v=edge[i].to;            if(deep[v]==-1 && edge[i].cap>0)            {                deep[v]=deep[u]+1;                que.push(v);            }        }    }    return deep[t]!=-1;}int dfs(int u,int t,int maxflow){    if(u==t || maxflow==0) return maxflow;    int flow=0;    for(int i=head[u];i!=-1; i=edge[i].next)    {        int v=edge[i].to;        if(deep[v]==deep[u]+1 && edge[i].cap>0)        {            int temp = dfs(v,t,min(edge[i].cap,maxflow-flow) );            if(temp)            {                edge[i].cap -=temp;                edge[i^1].cap+=temp;                flow += temp;                if(maxflow==flow) break;            }        }    }    if(!flow) deep[u]=-1;    return flow;}int dinic(int s,int t){    int ans=0;    while(bfs(s,t))    {        ans+=dfs(s,t,0x3f3f3f3f);    }    return ans;}


POJ 1149
做法:建图是关键

建立超级起点汇点,每个顾客用一个点表示。
超级起点向每个猪圈第一个客人连猪圈的初始权值
每个猪圈的第I个客户向第I+1的客户连一条容量为inf 的边。
每个客户向超级汇点连一个容量为其最大购买容量的边!


POJ 1637
做法:存在欧拉回路的充要条件为每个点出入度相等,有向边无法改变方向对出入度影响是定值,重点在于无向边,初始时方向随意,若此时存在某点的出入度之差为奇数则不存在欧拉回路。设每个点出度-入度为x。 则该点的权值为x/2 。每改变一条相连的边出入度差值改变为2, 删除所有有向边,x/2>0与起点 连一条边,否则与汇点连一条边,如果最后满流这就说明了 存在欧拉回路
#include <cstring>#include <cstdio>#include <algorithm>#include <queue>using namespace std;int n,m;const int maxn=3005;struct node{    int to,next,cap;}edge[maxn<<2];int head[maxn],cnt;void add(int u,int v,int w){    edge[cnt].to=v; edge[cnt].next=head[u];    edge[cnt].cap=w;  head[u]=cnt++;}int deep[maxn];int bfs(int s,int t){    memset(deep,-1,sizeof(deep));    deep[s]=0;    queue<int> que;    que.push(s);    while(!que.empty())    {        int u=que.front(); que.pop();        for(int i=head[u];i!=-1;i=edge[i].next)        {            int v=edge[i].to;            if(deep[v]==-1 && edge[i].cap>0)            {                deep[v]=deep[u]+1;                que.push(v);            }        }    }    return deep[t]!=-1;}int dfs(int u,int t,int maxflow){    if(u==t || maxflow==0) return maxflow;    int flow=0;    for(int i=head[u];i!=-1; i=edge[i].next)    {        int v=edge[i].to;        if(deep[v]==deep[u]+1 && edge[i].cap>0)        {            int temp = dfs(v,t,min(edge[i].cap,maxflow-flow) );            if(temp)            {                edge[i].cap -=temp;                edge[i^1].cap+=temp;                flow += temp;                if(maxflow==flow) break;            }        }    }    if(!flow) deep[u]=-1;    return flow;}int dinic(int s,int t){    int ans=0;    while(bfs(s,t))    {        ans+=dfs(s,t,0x3f3f3f3f);    }    return ans;}int in[maxn],out[maxn];void init(){    memset(head,-1,sizeof(head)); cnt=0;    memset(out,0,sizeof(out));    memset(in,0,sizeof(in));    scanf("%d%d",&n,&m);    for(int i=1;i<=m;++i)    {        int a,b,c;        scanf("%d%d%d",&a,&b,&c);        in[b]++ ;out[a]++;        if(c==0)        {            add(a,b,1); add(b,a,0);        }    }}int work(){    for(int i=1;i<=n;++i)    {        int temp=in[i]-out[i];        if( (temp%2+2)%2==1) return 0;    }    int sum=0;    for(int i=1;i<=n;++i)    {        int temp=out[i]-in[i];        if(temp>0)        {            add(0,i,temp/2); add(i,0,0);        }        else if(temp<0)        {            temp= -temp;            add(i,n+1,temp/2); add(n+1,i,0);sum+=(temp/2);        }    }    if(sum==dinic(0,n+1)) return 1;    return 0;}int main(){    int T;    scanf("%d",&T);    while(T--)    {        init();        if(work()) printf("possible\n");        else printf("impossible\n");    }    return 0;}

POJ 2391
做法:二分时间 检验的时候将小于mid的边都加入,判断是否满流即可(要用floyd求出各个点之间的最短路)
#include <stdio.h>#include <cstring>#include <algorithm>#include <queue>#include <iostream>using namespace std;typedef  long long ll;ll map[250][250];int a[25000],b[25000],n,m,sum;int s,t;struct node{    int to,next,cap;}edge[200*200*10];int head[250*10],cnt,deep[250*10];void add(int u,int v,int w){    edge[cnt].to=v; edge[cnt].next=head[u];    edge[cnt].cap=w;  head[u]=cnt++;}int bfs(int s,int t){    memset(deep,-1,sizeof(deep));    deep[s]=0;    queue<int> que;    que.push(s);    while(!que.empty())    {        int u=que.front(); que.pop();        for(int i=head[u];i!=-1;i=edge[i].next)        {            int v=edge[i].to;            if(deep[v]==-1 && edge[i].cap>0)            {                deep[v]=deep[u]+1;                que.push(v);            }        }    }    return deep[t]!=-1;}int dfs(int u,int t,int maxflow){    if(u==t || maxflow==0) return maxflow;    int flow=0;    for(int i=head[u];i!=-1; i=edge[i].next)    {        int v=edge[i].to;        if(deep[v]==deep[u]+1 && edge[i].cap>0)        {            int temp = dfs(v,t,min(edge[i].cap,maxflow-flow) );            if(temp)            {                edge[i].cap -=temp;                edge[i^1].cap+=temp;                flow += temp;                if(maxflow==flow) break;            }        }    }    if(!flow) deep[u]=-1;    return flow;}void gettu(ll mid){    s=0; t=2*n+1;    memset(head,-1,sizeof(head));    cnt=0;    for(int i=1;i<=n;++i)    {        add(s,i,a[i]);  add(i,s,0);        add(i+n,t,b[i]);    add(t,i+n,0);    }    for(int i=1;i<=n;++i)    {        for(int j=1;j<=n;++j)        {            if(map[i][j]<=mid)            {                add(i,j+n,0x3f3f3f3f);                add(j+n,i,0);            }        }    }}int dinic(ll mid){    gettu(mid);    int ans=0;    while(bfs(s,t))    {        ans+=dfs(s,t,0x3f3f3f3f);    }    if(ans==sum) return 1;    return 0;}int main(){    while(~scanf("%d%d",&n,&m))    {        sum=0;        for(int i=1;i<=n;++i)        {            for(int j=1;j<=n;++j)            {                map[i][j]=1LL<<60;            }            map[i][i]=0;        }        for(int i=1;i<=n;++i)        {            scanf("%d%d",&a[i],&b[i]);            sum+=a[i];        }        for(int i=0;i<m;++i)        {            int x,y; ll w;            scanf("%d%d%lld",&x,&y,&w);            if(map[x][y]>w)            {                map[x][y]=map[y][x]=w;            }        }        ll maxn=0;        for(int i=1;i<=n;++i)        {            for(int j=1;j<=n;++j)            {                for(int k=1;k<=n;++k)                {                    map[j][k] = min(map[j][k],map[j][i]+map[i][k]);                    if(map[j][k]!=(1LL<<60)) maxn=max(maxn,map[j][k]);                }            }        }        ll l=0,r=maxn+5, ans=-1,mid;        while(r>=l)        {            mid=(l+r)/2;            gettu(mid);            if(dinic(mid)) { r=mid-1; ans=mid; }            else  l=mid+1;        }        printf("%lld\n",ans);    }}


最小割:

Hoj:2634

做法:最大权闭合子图问题,答案为 all(权值)-最小割==最大流

#include <cstring>#include <cstdio>#include <cmath>#include <queue>#include <algorithm>typedef long long ll;using namespace std;int n,m;const int maxn=10000;struct node{    int to,next,cap;}edge[maxn<<2];int head[maxn],cnt;void add(int u,int v,int w){    edge[cnt].to=v; edge[cnt].next=head[u];    edge[cnt].cap=w;  head[u]=cnt++;}int deep[maxn];int bfs(int s,int t){    memset(deep,-1,sizeof(deep));    deep[s]=0;    queue<int> que;    que.push(s);    while(!que.empty())    {        int u=que.front(); que.pop();        for(int i=head[u];i!=-1;i=edge[i].next)        {            int v=edge[i].to;            if(deep[v]==-1 && edge[i].cap>0)            {                deep[v]=deep[u]+1;                que.push(v);            }        }    }    return deep[t]!=-1;}int dfs(int u,int t,int maxflow){    if(u==t || maxflow==0) return maxflow;    int flow=0;    for(int i=head[u];i!=-1; i=edge[i].next)    {        int v=edge[i].to;        if(deep[v]==deep[u]+1 && edge[i].cap>0)        {            int temp = dfs(v,t,min(edge[i].cap,maxflow-flow) );            if(temp)            {                edge[i].cap -=temp;                edge[i^1].cap+=temp;                flow += temp;                if(maxflow==flow) break;            }        }    }    if(!flow) deep[u]=-1;    return flow;}int dinic(int s,int t){    int ans=0;    while(bfs(s,t))    {        ans+=dfs(s,t,0x3f3f3f3f);    }    return ans;}int main(){    int T;    scanf("%d",&T);    while(T--)    {        scanf("%d%d",&m,&n);        memset(head,-1,sizeof(head));        cnt=0;        int sum=0,a;        for(int i=1;i<=m;++i)        {            scanf("%d",&a);            add(0,i,a); add(i,0,0);            sum+=a;        }        for(int i=1;i<=n;++i)        {              scanf("%d",&a);              add(i+m,n+m+1,a); add(n+m+1,i+m,0);        }        for(int i=1;i<=m;++i)        {             int k;             scanf("%d",&k);             while(k--)             {                 scanf("%d",&a);                 add(i,a+m+1,0x3f3f3f3f);                 add(a+m+1,i,0);             }        }        printf("%d\n",sum-dinic(0,n+m+1));    }    return 0;}

Hoj2713

做法:二分图最大点权独立集;(如同黑白染色)

注意: 二分图最大点权独立集+二分图最小点权覆盖集==ALL

#include <iostream>#include <stdio.h>#include <cstring>#include <queue>using namespace std;int n,m,sum;const int maxn=3000;struct node{    int to,next,cap;}edge[1000001];int head[maxn],cnt;void add(int u,int v,int w){    edge[cnt].to=v; edge[cnt].next=head[u];    edge[cnt].cap=w;  head[u]=cnt++;}int deep[maxn];int bfs(int s,int t){    memset(deep,-1,sizeof(deep));    deep[s]=0;    queue<int> que;    que.push(s);    while(!que.empty())    {        int u=que.front(); que.pop();        for(int i=head[u];i!=-1;i=edge[i].next)        {            int v=edge[i].to;            if(deep[v]==-1 && edge[i].cap>0)            {                deep[v]=deep[u]+1;                que.push(v);            }        }    }    return deep[t]!=-1;}int dfs(int u,int t,int maxflow){    if(u==t || maxflow==0) return maxflow;    int flow=0;    for(int i=head[u];i!=-1; i=edge[i].next)    {        int v=edge[i].to;        if(deep[v]==deep[u]+1 && edge[i].cap>0)        {            int temp = dfs(v,t,min(edge[i].cap,maxflow-flow) );            if(temp)            {                edge[i].cap -=temp;                edge[i^1].cap+=temp;                flow += temp;                if(maxflow==flow) break;            }        }    }    if(!flow) deep[u]=-1;    return flow;}int dinic(int s,int t){    int ans=0;    while(bfs(s,t))    {        ans+=dfs(s,t,0x3f3f3f3f);    }    return ans;}int in[60][60];int g[60][60];int dir[4][2]= { {1,0} , {-1,0} , {0,-1} , {0,1} };int id;bool check(int x,int y){    if(x<=0||y<=0||x>n||y>m)  return 0;    return 1;}int main(){    int T;    scanf("%d",&T);    while(T--)    {        memset(in,0,sizeof(in));        id=0;        sum=0;        scanf("%d%d",&n,&m);        for(int i=1;i<=n;++i)        {            for(int j=1;j<=m;++j)            {                ++id;                scanf("%d",&g[i][j]);                in[i][j]=id;                sum+=g[i][j];            }        }        memset(head,-1,sizeof(head));        cnt=0;        int s=0,t=n*m+1;        for(int i=1;i<=n;++i)        {            for(int j=1;j<=m;++j)            {                int id=in[i][j];                if((i+j)&1)                {                    add(id,t,g[i][j]); add(t,id,0);                }                else                {                    add(s,id,g[i][j]);                    add(id,s,0);                    for(int k=0;k<4;++k)                    {                       int x= i +dir[k][0];                       int y= j +dir[k][1];                       if(!check(x,y)) continue;                       add(id,in[x][y],0x3f3f3f3f); add(in[x][y],id,0);                    }                }            }        }        printf("%d\n",sum-dinic(s,t));    }    return 0;}





原创粉丝点击