【网络流近期整理】【最小割模型】

To-do LIST


【bzoj2055】80人环游世界 有上下界的费用流
https://blog.csdn.net/u012288458/article/details/50748608
hdu 6118 度度熊的交易计划(最小费用可行流)
https://blog.csdn.net/wang2147483647/article/details/77160903
hdu 4411 Arrest(费用流)
https://blog.csdn.net/kksleric/article/details/8009882


Pro1


F - Plug It In Gym - 101873F
Plug It In!
Adam just moved into his new apartment and simply placed everything into it at random. This
means in particular that he did not put any effort into placing his electronics in a way that each
one can have its own electric socket.
Since the cables of his devices have limited reach, not every device can be plugged into every
socket without moving it first. As he wants to use as many electronic devices as possible right
away without moving stuff around, he now tries to figure out which device to plug into which
socket. Luckily the previous owner left behind a plugbar which turns one electric socket into 3.
Can you help Adam figure out how many devices he can power in total?
Input
The input consists of:
• one line containing three integers m, n and k, where
– m (1 ≤ m ≤ 1 500) is the number of sockets;
– n (1 ≤ n ≤ 1 500) is the number of electronic devices;
– k (0 ≤ k ≤ 75 000) is the number of possible connections from devices to sockets.
• k lines each containing two integers xi and yi
indicating that socket xi can be used to
power device yi
.
Sockets as well as electronic devices are numbered starting from 1.
The plugbar has no cable, i.e. if it is plugged into a socket it simply triples it.
Output
Output one line containing the total number of electrical devices Adam can power.
Sample Input 1 Sample Output 1
3 6 8
1 1
1 2
1 3
2 3
2 4
3 4
3 5
3 6
5
GCPC 2017 Problem F: Plug It In! 11
Sample Input 2 Sample Output 2
4 5 11
1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3
4 4
4 5
5
Sample Input 3 Sample Output 3
3 5 7
1 1
1 2
2 2
2 3
2 4
3 4
3 5


有m个插座,n个电器,k个链接,每个插座都只能连接一个电器,现在有一个插座能够连接3个电器,问最多能给多少个电器充电。
建图,把源点到插座的边都记录下来,先跑一遍最大流,然后保存一下残余网路,枚举能连接3个电器的那个插座,然后在保存下来的残余网路上跑最大流即可。
注意此题的边和点的数组设置要极为准确,既不能过大也不能过小。


Pro2: UVALive - 3487 Duopoly(最小割)
2015年08月31日 13:58:30 阅读数:509更多
个人分类: ACM-图论-网络流
题目大意:有两个公司A和B在申请一些资源
现在给出两个公司所申请的内容,内容包括价钱和申请的资源
现在你做为官方,你只能拒绝一个申请或者接受一个申请,同一个资源不能两个公司都拥有,且申请的资源不能只给部分
问:作为官方,你能得到的最大利益是多少

解题思路:这题的矛盾在于,同一个资源不能两家公司共享,既然如此的话,那就找出矛盾的申请,让他们之间连条线就可以了,容量为INF
设立源点,源点和A公司的申请相连接,容量为申请的价钱
设立汇点,汇点和B公司的申请相连接,容量为申请的价钱
然后找出矛盾的申请,连线。因为只有矛盾的申请才能连线,且只有连线的才能把流流到汇点,所以跑出来的最大流就是我们所需要的最小割
所以答案就是所有申请的价钱总和 - 最小割
参考博客
坑点:标记数组没有清空一直wa。


Pro3 Catering
bzoj 4108: [Wf2015]Catering (有源汇有上下界的费用流)
4108: [Wf2015]Catering
Time Limit: 4 Sec Memory Limit: 128 MB
Submit: 165 Solved: 58
[Submit][Status][Discuss]
Description
有一家装备出租公司收到了按照时间顺序排列的n个请求.

这家公司有k个搬运工.每个搬运工可以搬着一套装备按时间顺序去满足一些请求.一个搬运工从第i个请求的位置把东西搬到第j个请求的位置需要一些费用.公司的编号是1,请求的编号是2到n+1.所有搬运工必需从公司出发.
求满足所有请求所需的最小搬运费用.
Input
有可能有多组数据(我也不知道).

第一行两个正整数n,k.
接下来n行,第i行有n-i+1个数.第j个数表示把装备从i搬到i+j的花费.
Output
输出一行一个整数表示最小花费.

Sample Input
1 1
10
Sample Output
10
HINT
n, k <= 100;

花费 <= 1,000,000
Source
鸣谢laekov提供译文

[Submit][Status][Discuss]

题解:有源汇有上下界的费用流

建出原图后重建,直接跑最小费用最大流即可。注意要加权限制总的路线数。
提交地址:
https://open.kattis.com/submissions/3003606
code:
wf2015 题解 https://tieba.baidu.com/p/3778682428?red_tag=1761530858
https://blog.csdn.net/Phenix_2015/article/details/51158707

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstring>
#define N 50000
#define inf 1000000000
using namespace std;
int ans,n,m,tot,val[N];
int point[N],v[N],Next[N],remain[N],c[N],dis[N],can[N],last[N];
void add(int x,int y,int z,int k)
{
    tot++; Next[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=z; c[tot]=k;
    tot++; Next[tot]=point[y]; point[y]=tot; v[tot]=x; remain[tot]=0; c[tot]=-k;
    //if (z)  cout<<x<<" "<<y<<" "<<z<<" "<<k<<endl;
}
int addflow(int s,int t)
{
    int now=t; int ans=inf;
    while (now!=s) {
        //cout<<now<<" ";
        ans=min(ans,remain[last[now]]);
        now=v[last[now]^1];
    }
    //cout<<now<<endl;
    now=t;
    while (now!=s) {
        remain[last[now]]-=ans;
        remain[last[now]^1]+=ans;
        now=v[last[now]^1];
    }
    return ans;
}
bool spfa(int s,int t)
{
    for (int i=0;i<=t;i++) dis[i]=inf,can[i]=0;
    dis[s]=0; can[s]=1;
    queue<int> p; p.push(s);
    while (!p.empty()){
        int now=p.front(); p.pop();
        for (int i=point[now];i!=-1;i=Next[i])
         if (remain[i]&&dis[v[i]]>dis[now]+c[i]){
            dis[v[i]]=dis[now]+c[i];
            last[v[i]]=i;
            if (!can[v[i]]) {
                can[v[i]]=1;
                p.push(v[i]);
             }
         }
        can[now]=0;
    }
    if (dis[t]==inf) return false;
    int mx=addflow(s,t);
    //cout<<dis[t]<<" "<<mx<<endl;
    ans+=mx*dis[t];
    return true;
}
void solve(int s,int t)
{
    while (spfa(s,t));
}
int main()
{
//  freopen("a.in","r",stdin);
//  freopen("my.out","w",stdout);
    while (scanf("%d%d",&n,&m)!=EOF) {
        tot=-1;
        memset(point,-1,sizeof(point));
        int t=2*(n+1)+1;
        for (int i=1;i<=n;i++) {
         int x; scanf("%d",&x);
         add(1,i+1,1,x);
        }
        for (int i=1;i<=n;i++)
         for (int j=i+1;j<=n;j++){
          int x; scanf("%d",&x);
          add(i+n+1,j+1,1,x);
        }
        for (int i=1;i<=n;i++)
         add(i+1,i+n+1,0,0),add(i+n+1,t,1,0);
        int S=t+1; int T=t+2;
        add(t,0,inf,0); add(0,1,m,0); //add(S,1,1,0); add(0,T,1,0);

//        这里转换为无源汇的网络流是通过增加一个点0来将源点和汇点连接起来的
//        或者改为 add(t,1,m,0); 
        for (int i=2;i<=n+1;i++)
         add(S,i+n,1,0),add(i,T,1,0);
        solve(S,T);
        printf("%d\n",ans);
    }
}

Pro1 code:

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 10516;//点数的最大值
const int MAXM = 75100;//边数的最大值
const int INF = 0x3f3f3f3f;
struct Edge
{
    int to,next,cap,flow;

} edge[250000],temp[250000]; //注意是 MAXM
int tol;
int head[10000],book[10000],n,m,k;
void init()
{
    tol = 2;
    memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int w,int rw = 0)
{
    edge[tol].to = v;
    edge[tol].cap = w;
    edge[tol].flow = 0;
    edge[tol].next = head[u];
    head[u] = tol++;

    edge[tol].to = u;
    edge[tol].cap = rw;
    edge[tol].flow = 0;
    edge[tol].next = head[v];
    head[v] = tol++;
}
int Q[MAXN];
int dep[MAXN],cur[MAXN],sta[MAXN];
bool bfs(int s,int t,int n)
{
    int front = 0,tail = 0;
    memset(dep,-1,sizeof(dep[0])*(n+1));
    dep[s] = 0;
    Q[tail++] = s;
    while(front < tail)
    {
        int u = Q[front++];
        for(int i = head[u]; i != -1; i = edge[i].next)
        {
            int v = edge[i].to;
            if(edge[i].cap > edge[i].flow && dep[v] == -1)
            {
                dep[v] = dep[u] + 1;
                if(v == t)return true;
                Q[tail++] = v;
            }
        }
    }
    return false;
}
int dinic(int s,int t,int n)
{
    int maxflow = 0;
    while(bfs(s,t,n))
    {
        for(int i = 0; i < n; i++)cur[i] = head[i];
        int u = s, tail = 0;
        while(cur[s] != -1)
        {
            if(u == t)
            {
                int tp = INF;
                for(int i = tail-1; i >= 0; i--)
                    tp = min(tp,edge[sta[i]].cap-edge[sta[i]].flow);
                maxflow += tp;
                for(int i = tail-1; i >= 0; i--)
                {
                    edge[sta[i]].flow += tp;
                    edge[sta[i]^1].flow -= tp;
                    if(edge[sta[i]].cap-edge[sta[i]].flow == 0)
                        tail = i;
                }

                u = edge[sta[tail]^1].to;
            }
            else if(cur[u] != -1 && edge[cur[u]].cap > edge[cur[u]].flow && dep[u] + 1 == dep[edge[cur[u]].to])
            {
                sta[tail++] = cur[u];
                u = edge[cur[u]].to;
            }
            else
            {
                while(u != s && cur[u] == -1)
                    u = edge[sta[--tail]^1].to;
                cur[u] = edge[cur[u]].next;
            }
        }
    }
    return maxflow;
}

int main()
{

    init();
    scanf("%d%d%d",&n,&m,&k);

    for(int i=1; i<=n; i++)
    {
        //add_e(0,i,1);//
        addedge(0,i,1);
        book[i] =tol-2 ;

    }
    while(k--)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        addedge(u,v+n,1);
    }
    for(int i=1; i<=m; i++)
    {
        addedge(n+i,n+m+1,1);

    }

    int ans2 = dinic(0,m+n+1,n+m+2);
    memcpy(temp,edge,sizeof temp);
    int ans = 0;
    for(int i=1; i<=n; i++)
    {
        memcpy(edge,temp,sizeof temp);
      //  edge[book[i]].flow+=2;
        edge[book[i]].cap+=2;
        ans = max(ans,dinic(0,n+m+1,n+m+2));
    }
    printf("%d\n",ans2+ans);
    return 0;
}

Pro2 code:


#include<bits/stdc++.h>
using namespace std;
const int MAXN = 10516;//点数的最大值
const int MAXM = 75100;//边数的最大值
const int INF = 0x3f3f3f3f;
struct Edge
{
    int to,next,cap,flow;

} edge[1250000]; //注意是 MAXM
int tol;
int head[120000],n,m,k;
void init()
{
    tol = 0;
    memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int w,int rw = 0)
{
    edge[tol].to = v;
    edge[tol].cap = w;
    edge[tol].flow = 0;
    edge[tol].next = head[u];
    head[u] = tol++;

    edge[tol].to = u;
    edge[tol].cap = rw;
    edge[tol].flow = 0;
    edge[tol].next = head[v];
    head[v] = tol++;
}
int Q[MAXN];
int dep[MAXN],cur[MAXN],sta[MAXN];
bool bfs(int s,int t,int n)
{
    int front = 0,tail = 0;
    memset(dep,-1,sizeof(dep[0])*(n+1));
    dep[s] = 0;
    Q[tail++] = s;
    while(front < tail)
    {
        int u = Q[front++];
        for(int i = head[u]; i != -1; i = edge[i].next)
        {
            int v = edge[i].to;
            if(edge[i].cap > edge[i].flow && dep[v] == -1)
            {
                dep[v] = dep[u] + 1;
                if(v == t)return true;
                Q[tail++] = v;
            }
        }
    }
    return false;
}
int dinic(int s,int t,int n)
{
    int maxflow = 0;
    while(bfs(s,t,n))
    {
        for(int i = 0; i < n; i++)cur[i] = head[i];
        int u = s, tail = 0;
        while(cur[s] != -1)
        {
            if(u == t)
            {
                int tp = INF;
                for(int i = tail-1; i >= 0; i--)
                    tp = min(tp,edge[sta[i]].cap-edge[sta[i]].flow);
                maxflow += tp;
                for(int i = tail-1; i >= 0; i--)
                {
                    edge[sta[i]].flow += tp;
                    edge[sta[i]^1].flow -= tp;
                    if(edge[sta[i]].cap-edge[sta[i]].flow == 0)
                        tail = i;
                }

                u = edge[sta[tail]^1].to;
            }
            else if(cur[u] != -1 && edge[cur[u]].cap > edge[cur[u]].flow && dep[u] + 1 == dep[edge[cur[u]].to])
            {
                sta[tail++] = cur[u];
                u = edge[cur[u]].to;
            }
            else
            {
                while(u != s && cur[u] == -1)
                    u = edge[sta[--tail]^1].to;
                cur[u] = edge[cur[u]].next;
            }
        }
    }
    return maxflow;
}
int booka[400000],bookb[400000];
int price[400000],price2[400000];
int vis[3100][3100];
int main()
{

    int T;
    cin>>T;
    int y = 0;
    int top =1;

    while(T--)

    {
        if(top)top =0;
        else printf("\n");
        y++;

        init();
        cin>>n;
        memset(vis,0,sizeof vis);
        memset(booka,0,sizeof booka);
        memset(bookb,0,sizeof bookb);
        //memset(vis,0,sizeof vis);
        int Max = -0x3f3f3f3f;
        int a,b;
        int sum  =0;
            string tmp;
         //

       //   getline(cin,tmp);
        for(int i=1; i<=n; i++)
        {

//            getline(cin,tmp);
//            stringstream p(tmp);
            cin>>price[i];
           //   cout<<a<<" " ;
            sum+=price[i];
            char ch =0;
            while(ch!='\n'&&scanf("%d%c",&b,&ch)==2)
            {
                 //    cout<<b<<" " ;
                Max=  max(Max,b);
                booka[b] = i;
            }
           // cout<<endl;
        }
          //getline(cin,tmp);
          cin>>m;
        for(int i=1; i<=m; i++)
        {
            //string tmp;
            //getline(cin,tmp);
            //stringstream p(tmp);
            cin>>price2[i];
            sum+=price2[i];
           // cout<<a<<" " ;
           char ch =0;
            while(ch!='\n'&&scanf("%d%c",&b,&ch)==2)
            {
               // cout<<b<<" " ;
                Max=  max(Max,b);
                bookb[b] = i;
            }
          //  cout<<endl;
        }
        for(int i=1; i<=n; i++)
        {
            addedge(0,i,price[i]);
        }
        for(int i=1; i<=m; i++)
        {
            addedge(n+i,n+m+1,price2[i]);
        }
        for(int i=1; i<=Max; i++)
        {
            if(!booka[i]||!bookb[i]||vis[booka[i]][bookb[i]])continue;
            vis[booka[i]][bookb[i]] = 1;
            addedge(booka[i],bookb[i]+n,0x3f3f3f3f);
        }
        int ans = dinic(0,n+m+1,n+m+2);
        printf("Case %d:\n",y);
        cout<<sum-ans<<endl;

    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/axuhongbo/article/details/82021192