把给定的每种相同的时间段成一个点,再把每一天抽象成一个点,每一天都与汇点连一条容量为0的边(以后需要扩张,所以一开始设为0)。
然后对于每个时间段,都对他对应的天连一条容量为INF的边。
然后这里需要用到一个mp数组,用来存储时间段对应的边的序号,mp[x][y]即为源点到 " 范围为x~y的区间代表的点 "的边的序号。对于每个人建立区间的时候,先看他对应的区间有没有被建立,如果没有的话就建立这个区间,然后从源点到这个区间所代表的点连一条容量为1的边,在mp中记录边的序号。如果已经建立了,就为源点到这个区间的边容量+1(我们可以从mp中得到边的序号)。随后,跑一边最大流,如果最大流小于当前的人数,则说明需要扩张”代表天的点到汇点“的边的容量,所以我们打印出这个人的序号,然后为”代表天的点到汇点“的边容量+1(因为我们最先连接的就是这些边,所以他们的编号就是0~2*d,这里要把反向边算进去),然后继续遍历下一个点即可。
所以我们为什么要搞的这么复杂呢?直接把每个人都设成一个点不行吗?
这里是考虑到时间复杂度,因为最多有20天,所以最多只有400个区间,而人数有10000个,这样建图可以极大的减少点的数量,加快速度。
#include <iostream>
#include <algorithm>
#include <string>
#include <stdio.h>
#include <cstdlib>
#include <math.h>
#include <cstring>
#include <iomanip>
#include <vector>
#include <queue>
using namespace std;
#define ll long long
#define N 1010
#define INF 0x3f3f3f3f
int mp[21][21];
int s,t;
struct Edge{
int from,to,cap,flow;
Edge(int a = 0,int b = 0,int c = 0,int d = 0){
from = a,to = b,cap = c,flow = d;
}
};
vector<Edge>edges;
vector<int>G[N];
bool vis[N];
int deep[N],cur[N];
void init(){
edges.clear();
for(int i=0;i<N;i++){
G[i].clear();
}
}
void guiling(){
int m = edges.size();
for(int i = 0 ;i<m;i++){
edges[i].flow = 0;
}
}
void addedges(int from,int to,int cap){
edges.push_back(Edge(from,to,cap,0));
edges.push_back(Edge(to,from,0,0));
int m = edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
bool bfs(){
memset(vis,0,sizeof(vis));
queue<int>Q;
Q.push(s);
vis[s] = 1;deep[s] = 1;
while (!Q.empty())
{
int x = Q.front();Q.pop();
for(int i = 0 ;i < G[x].size(); i++){
Edge &e = edges[G[x][i]];
if(!vis[e.to] && e.cap > e.flow){
deep[e.to] = deep[x] + 1;
vis[e.to] = 1;
Q.push(e.to);
}
}
}
return vis[t];
}
int dfs(int x,int a){
if(x == t || a == 0){
return a;
}
int flow = 0,f;
for(int &i = cur[x];i<G[x].size();i++){
Edge &e = edges[G[x][i]];
if(deep[x] +1 == deep[e.to] && (f = dfs(e.to,min(e.cap - e.flow,a))) > 0){
e.flow += f;
edges[G[x][i]^1].flow -= f;
flow += f;
a -= f;
if(a == 0){
break;
}
}
}
return flow;
}
int MaxFlow(){
int flow = 0;
while (bfs())
{
memset(cur,0,sizeof(cur));
flow += dfs(s,INF);
}
return flow;
}
int n,d;
int main(){
int i,j,k,x,y;
//freopen("abc.txt","w",stdout);
while (scanf("%d",&n),n)
{
scanf("%d",&d);
init();
memset(mp,-1,sizeof(mp));
s = 0,t = 1000;
for(i=1;i<=d;i++){
addedges(i,t,0);
}
int cnt = d;//为区域标号
vector<int>ans;
for(i=1;i<=n;i++){
scanf("%d%d",&x,&y);
if(mp[x][y] == -1){
cnt++;
addedges(s,cnt,1);
mp[x][y] = edges.size() - 2;//记录下是哪两条边
for(j=x;j<=y;j++){
addedges(cnt,j,INF);
}
}else{
edges[mp[x][y]].cap++;
edges[mp[x][y]+1].cap++;
}
int p = MaxFlow();
guiling();
if(p < i){
for(j = 0;j< d * 2;j++){
edges[j].cap++;
}
ans.push_back(i);
}
}
for(i = 0;i< ans.size() - 1;i++){
printf("%d ",ans[i]);
}
printf("%d",ans[ans.size()-1]);
printf("\n");
}
return 0;
}