UVALive 8275 网络流

把给定的每种相同的时间段成一个点,再把每一天抽象成一个点,每一天都与汇点连一条容量为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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值