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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章