2017 暑假艾教集訓 day12 網絡流(最大流 最小割)!

模板

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;
}





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章