Codeforces 976F

题意略。

思路:为了保证每个点都有至少k条边覆盖,我们可以让二分图的左半边与源点s相连,连容量为indegree[i] - k的边(如果正着想不好想,我们可以想它的反面,

限制它反面的上限,从而保证我正面k条边的覆盖),让二分图的右半边与汇点t相连,容量同样是indegree[i] - k。然后跑最大流,E - 最大流中用到的边 = 答案。

每次跑完最大流都要重新建图。我的最大流用的是dinic。

详见代码:

#include<bits/stdc++.h>
#define maxn 4005
#define INF 0x3f3f3f3f
using namespace std;

struct edge{
    int to,cap,rev,id;
    edge(int a = 0,int b = 0,int c = 0,int d = 0){
        to = a,cap = b,rev = c,id = d;
    }
};

bool visit[maxn];
int indg[maxn],level[maxn],iter[maxn],n1,n2,m,s,t,store[maxn];
vector<edge> graph[maxn];
vector<edge> standard[maxn];

void add_e(int from,int to,int cap,int id){
    graph[from].push_back(edge(to,cap,graph[to].size(),id));
    graph[to].push_back(edge(from,0,graph[from].size() - 1,id));
}
void bfs(int s){
    memset(level,-1,sizeof(level));
    queue<int> que;
    level[s] = 0;
    que.push(s);
    while(que.size()){
        int v = que.front();
        que.pop();
        for(int i = 0;i < graph[v].size();++i){
            edge& e = graph[v][i];
            if(e.cap > 0 && level[e.to] < 0){
                level[e.to] = level[v] + 1;
                que.push(e.to);
            }
        }
    }
}
int dfs(int v,int t,int f){
    if(v == t) return f;
    for(int& i = iter[v];i < graph[v].size();++i){
        edge& e = graph[v][i];
        if(e.cap > 0 && level[v] < level[e.to]){
            int d = dfs(e.to,t,min(f,e.cap));
            if(d > 0){
                e.cap -= d;
                graph[e.to][e.rev].cap += d;
                return d;
            }
        }
    }
    return 0;
}
int max_flow(int s,int t){
    int flow = 0;
    while(true){
        bfs(s);
        if(level[t] < 0) return flow;
        memset(iter,0,sizeof(iter));
        int f;
        while((f = dfs(s,t,INF)) > 0){
            flow += f;
        }
    }
}

int main(){
    scanf("%d%d%d",&n1,&n2,&m);
    s = 0,t = n1 + n2 + 1;
    for(int i = 0;i < m;++i){
        int u,v;
        scanf("%d%d",&u,&v);
        v += n1;
        ++indg[u],++indg[v];
        standard[u].push_back(edge(v,1,standard[v].size(),i + 1));
        standard[v].push_back(edge(u,0,standard[u].size() - 1,i + 1));
    }
    int mdg = maxn;
    for(int i = 1;i <= n1 + n2;++i)
        mdg = min(mdg,indg[i]);
    printf("0\n");
    for(int k = 1;k <= mdg;++k){
        for(int v = 0;v < maxn;++v) graph[v].clear();
        for(int i = 1;i <= n1 + n2;++i){
            for(int j = 0;j < standard[i].size();++j)
                graph[i].push_back(standard[i][j]);
        }
        for(int i = 1;i <= n1;++i) add_e(s,i,indg[i] - k,-1);
        for(int i = n1 + 1;i <= n1 + n2;++i) add_e(i,t,indg[i] - k,-1);
        max_flow(s,t);
        memset(visit,false,sizeof(visit));
        int cnt = 0;
        for(int i = n1 + 1;i <= n1 + n2;++i){
            for(int j = 0;j < graph[i].size();++j){
                edge& e = graph[i][j];
                if(e.cap && e.to != t){
                    visit[e.id] = true;
                    ++cnt;
                }
            }
        }
        printf("%d",m - cnt);
        for(int i = 1;i <= m;++i){
            if(!visit[i]) printf(" %d",i);
        }
        printf("\n");
    }
    return 0;
}

/*
1 2 10
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 2
*/

猜你喜欢

转载自www.cnblogs.com/tiberius/p/9032098.html