Codeforces 976F Minimal k-covering【最大流】

题意:给一个二分图,存在重边,求使各点度数至少为k(0<=k<=min(d[i]))的最小边集合。

分析:首先建立一个源点s向二分图左边连边,建立一个汇点e,所有二分图右边的点向e点连边。要使每个点的度数大于等于k,可使流过每个点的流量小于等于d[i]-k。(d[i]为每个点的度数),就可以在建立源点到二分图左边点,和二分图右边点到汇点时开始限制。然后对每个k跑一遍最大流,记录一下剩余的边即是正确答案。

You are given a bipartite graph G = (U, V, E), U is the set of vertices of the first part, V is the set of vertices of the second part and E is the set of edges. There might be multiple edges.

Let's call some subset of its edges  k-covering iff the graph  has each of its vertices incident to at least k edges. Minimal k-covering is such a k-covering that the size of the subset  is minimal possible.

Your task is to find minimal k-covering for each , where minDegreeis the minimal degree of any vertex in graph G.

Input

The first line contains three integers n1n2 and m (1 ≤ n1, n2 ≤ 2000, 0 ≤ m ≤ 2000) — the number of vertices in the first part, the number of vertices in the second part and the number of edges, respectively.

The i-th of the next m lines contain two integers ui and vi (1 ≤ ui ≤ n1, 1 ≤ vi ≤ n2) — the description of the i-th edge, ui is the index of the vertex in the first part and vi is the index of the vertex in the second part.

Output

For each  print the subset of edges (minimal k-covering) in separate line.

The first integer cntk of the k-th line is the number of edges in minimal k-covering of the graph. Then cntk integers follow — original indices of the edges which belong to the minimal k-covering, these indices should be pairwise distinct. Edges are numbered 1 through m in order they are given in the input.

Examples

Input
3 3 7
1 2
2 3
1 3
3 2
3 3
2 1
2 1
Output
0 
3 3 7 4
6 1 3 6 7 4 5
Input
1 1 5
1 1
1 1
1 1
1 1
1 1
Output
0 
1 5
2 4 5
3 3 4 5
4 2 3 4 5
5 1 2 3 4 5

#include<bits/stdc++.h>
using namespace std;
const int N=4010;
vector<int>g[N],num[N],ans[N];
int f[N][N],tem[N][N],n,m,d[N],cnt,v[N];
bool dfs(int x)
{
    if(x==n)return true;
    v[x]=cnt;
    for(int i=0;i<g[x].size();i++)
    {
        int y=g[x][i];
        if(f[x][y]==0||v[y]==cnt)continue;
            if(dfs(y))
            {
                f[x][y]--;
                f[y][x]++;
                return true;
            }
    }
    return false;
}
int main()
{
    int n1,n2,x,y,k;
    scanf("%d%d%d",&n1,&n2,&k);
    n=n1+n2+1;
    for(int i=1;i<=k;i++)
    {
        scanf("%d%d",&x,&y);
        y+=n1;
        g[x].push_back(y);
        g[y].push_back(x);
        num[x].push_back(i);
        f[x][y]++;
        d[x]++,d[y]++;
    }
        m=k*2;
    for(int i=1;i<n;i++)m=min(m,d[i]);
    for(int i=1;i<=n1;i++)
    {
        g[0].push_back(i);
        g[i].push_back(0);
        f[0][i]=d[i]-m;
    }
    for(int i=n1+1;i<n;i++)
    {
        g[i].push_back(n);
        g[n].push_back(i);
        f[i][n]=d[i]-m;
    }
    for(int l=m;l>=0;l--)
    {
        cnt++;
        while(dfs(0))cnt++;
        for(int i=1;i<=n1;i++)
        {
            for(int j=0;j<g[i].size();j++)
            {
                y=g[i][j];
                tem[i][y]=f[i][y];
            }
        }
        for(int i=1;i<=n1;i++)
        {
            for(int j=0;j<g[i].size();j++)
            {
                y=g[i][j];
                if(y&&tem[i][y])
                {
                    tem[i][y]--;
                    ans[l].push_back(num[i][j]);
                }
            }
        }
        for(int i=1;i<=n1;i++)f[0][i]++;
        for(int i=n1+1;i<n;i++)f[i][n]++;
    }
    for(int i=0;i<=m;i++)
    {
        printf("%d",ans[i].size());
        for(auto &x:ans[i])
            printf(" %d",x);
        printf("\n");
    }
}

猜你喜欢

转载自www.cnblogs.com/upstart/p/8982466.html
今日推荐