版权声明: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;
}