Gym - 101986H Homework (最大流和最小割)

版权声明:Why is everything so heavy? https://blog.csdn.net/lzc504603913/article/details/84317433

题意:有N个作业,分别为A类和B类,每天最多只能选择AB中的一类做,如果该天有该类的作业,就必须要做一个,问最多能做多少作业,和最少要做多少作业。

解题思路:对于最多能做多少,很容易建图

对于每一天建一个点

对于每一个作业建一个点

每个作业覆盖的天都跟该作业连边,流量为1

源点跟每一天连边,流量为1

每一个作业跟汇点连边,流量为1.

最大流即最多能做的作业。

其实就是个最大匹配过程。

最小怎么求呢?最小容易联想到最小割。因此把模型转化为最小割模型,每割一条边,代表做了那个作业,那么我们只要求出最小割,即求出了最小要做的作业。但是这里还有天数的限制,即每一天必须要做一个作业,除非没有该类作业。那么我们只要把天的限制也考虑进去即可。具体建图如下

把每一天拆点,变成800个点。起点与终点之间连边,流量为1

对于每一个A类作业,把A类作业覆盖的天,向该天的起点连边,流量为1.

对于每一个B类作业,把B类作业覆盖的天,向该天的终点连边,流量为1.

源点跟A类每一个点连边

B类每一个点向汇点连边

最后最小割即为所求。

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1605;
const int INF=0x3f3f3f3f;
typedef long long ll;

int N,M;

int cnt=0;
struct edge{
    int v,next,flow;
}e[800*800*2];

int head[MAXN],edge_num,layer[MAXN];

void insert_edge(int u,int v,int w){
    e[edge_num].v=v;
    e[edge_num].flow=w;
    e[edge_num].next=head[u];
    head[u]=edge_num++;
    e[edge_num].v=u;
    e[edge_num].flow=0;
    e[edge_num].next=head[v];
    head[v]=edge_num++;
}

bool bfs(int start,int End){
    queue<int> Q;
    Q.push(start);
    memset(layer,0,sizeof(layer));
    layer[start]=1;

    while (Q.size()) {
        int u=Q.front();
        Q.pop();
        if(u==End)
            return true;
        for(int j=head[u];~j;j=e[j].next){
            int v=e[j].v;
            if(layer[v]==false&&e[j].flow){
                layer[v]=layer[u]+1;
                Q.push(v);
            }
        }
    }
    return false;
}

int dfs(int u,int Maxflow,int End){
    if(u==End)
        return Maxflow;
    int uflow=0;
    for(int j=head[u];~j;j=e[j].next){
        int v=e[j].v;
        if(layer[v]-1==layer[u]&&e[j].flow){
            int flow=min(Maxflow-uflow,e[j].flow);
            flow=dfs(v,flow,End);
            e[j].flow-=flow;
            e[j^1].flow+=flow;
            uflow+=flow;
            if(uflow==Maxflow)
                break;
        }
    }
    if(uflow==0)
        layer[u]=0;
    return uflow;
}

int dinic(int start,int End){
    int Maxflow=0;
    while(bfs(start,End))
        Maxflow+=dfs(start,INF,End);
    return Maxflow;
}

struct point{
    int s,e;
}P[MAXN*4];

int in[MAXN],out[MAXN],tian1[MAXN],tian2[MAXN];

int main(){

    scanf("%d%d",&N,&M);

    for(int i=1;i<=N;i++)
        scanf("%d%d",&P[i].s,&P[i].e);

    memset(head,-1,sizeof(head));
    edge_num=0;
    cnt=0;

    int S,T;

    S=++cnt;
    for(int i=1;i<=400;i++)
        in[i]=++cnt;
    for(int i=1;i<=N;i++)
        out[i]=++cnt;
    T=++cnt;


    for(int i=1;i<=N;i++)
        for(int j=P[i].s;j<=P[i].e;j++)
            insert_edge(in[j],out[i],INF);

    for(int i=1;i<=400;i++)
        insert_edge(S,in[i],1);
    for(int i=1;i<=N;i++)
        insert_edge(out[i],T,1);

    int ans1=dinic(S,T);


    memset(head,-1,sizeof(head));
    edge_num=0;
    cnt=0;

    S=++cnt;
    for(int i=1;i<=M;i++)
        in[i]=++cnt;
    for(int i=M+1;i<=N;i++)
        out[i]=++cnt;
    for(int i=1;i<=400;i++)
        tian1[i]=++cnt;
    for(int i=1;i<=400;i++)
        tian2[i]=++cnt;
    T=++cnt;

    for(int i=1;i<=M;i++)
        insert_edge(S,in[i],1);

    for(int i=1;i<=M;i++)
        for(int j=P[i].s;j<=P[i].e;j++)
            insert_edge(in[i],tian1[j],1);

    for(int i=1;i<=400;i++)
        insert_edge(tian1[i],tian2[i],1);

    for(int i=M+1;i<=N;i++)
        for(int j=P[i].s;j<=P[i].e;j++)
            insert_edge(tian2[j],out[i],1);

    for(int i=M+1;i<=N;i++)
        insert_edge(out[i],T,1);


    int ans2=dinic(S,T);

    printf("%d\n%d",ans1,ans2);


    return 0;
}


猜你喜欢

转载自blog.csdn.net/lzc504603913/article/details/84317433
今日推荐