SGU 242 Student's Morning 网络流(水

来源:互联网 发布:mac怎么安装nodejs 编辑:程序博客网 时间:2024/05/22 15:43

题目链接:点击打开链接

题意:

给定n个人,m个终点

下面n行表示每个人可以去m个点。

每个人只能去一个点。

输出任意一个方案使得每个点至少有2个人到达。

若存在输出m行,第一个数字表示i这个点来了几个人,后面是人的点标。


思路:

建一个二部图n-m,然后m到汇点限流2,判断是否满流,若不满流就无解。

若满流则其他的人随便走。


#include <stdio.h>#include <string.h>#include <iostream>#include <math.h>#include <queue>#include <set>#include <algorithm>using namespace std;typedef int ll;#define N 420#define M 100000#define inf 107374182struct Edge{    ll from, to, cap, nex;}edge[M*2];ll head[N], edgenum;void add(ll u, ll v, ll cap, ll rw = 0){    Edge E = {u, v, cap, head[u]};    edge[edgenum] = E;    head[u] = edgenum ++;    Edge E2 = {v, u, rw, head[v]};    edge[edgenum] = E2;    head[v] = edgenum ++;}ll sign[N];bool BFS(ll from, ll to){    memset(sign, -1, sizeof sign);    sign[from] = 0;    queue<ll>q;    q.push(from);    while( !q.empty() ) {        ll u = q.front(); q.pop();        for(ll i = head[u]; ~i; i = edge[i].nex)        {            ll v = edge[i].to;            if(sign[v] == -1 && edge[i].cap){                sign[v] = sign[u] +1, q.push(v);                if(sign[to] != -1) return true;            }        }    }    return false;}ll Stack[N], top, cur[N];ll Dinic(ll from, ll to){    ll ans = 0;    while( BFS(from, to) )    {        memcpy(cur, head, sizeof head);        ll u = from; top = 0;        while(1)        {            if(u==to)            {                ll flow = inf, loc;                for(ll i = 0; i < top; i++)                    if(flow > edge[Stack[i]].cap)                    {                        flow = edge[Stack[i]].cap;                        loc = i;                    }                for(ll i = 0; i < top; i++)                {                    edge[ Stack[i] ].cap -= flow;                    edge[Stack[i]^1].cap += flow;                }                ans += flow;                top = loc;                u = edge[Stack[top]].from;            }            for(ll i = cur[u]; ~i; cur[u] = i = edge[i].nex)                if(edge[i].cap && (sign[u]+1 == sign[edge[i].to]))break;            if(cur[u] != -1){                Stack[top++] = cur[u];                u = edge[cur[u]].to;            }            else            {                if(top==0)break;                sign[u] = -1;                u = edge[Stack[--top]].from;            }        }    }    return ans;}void init(){memset(head, -1, sizeof head); edgenum = 0;}int n, m, from, to, to2, ans[N], G[N];vector<int>D[N];bool solve(){    from = 0; to = n+m+1; to2 = to+1;    init();    for(int i = 1; i <= n; i++)    {        G[i] = -1;        add(from, i, 1);        int x, y; scanf("%d",&x);        while(x--){            scanf("%d",&y);            G[i] = y;            add(i, n+y, 1);        }    }    for(int i = 1; i <= m; i++)        add(n+i, to, 2);    add(to, to2, inf);    if(m*2 > n || Dinic(from, to2) < m*2)return false;    puts("YES");    for(int i = 1; i <= n; i++)    {        ans[i] = -1;        for(int j = head[i]; ~j; j = edge[j].nex)        {            if(edge[j].cap==0 && edge[j].to != from)            {                ans[i] = edge[j].to-n;                D[edge[j].to-n].push_back(i);                break;            }        }        if(ans[i]==-1 && G[i]!=-1)            D[G[i]].push_back(i);    }    for(int i = 1; i <= m; i++)    {        printf("%d", D[i].size());        for(int j = 0; j < D[i].size(); j++)            printf(" %d", D[i][j]);        puts("");    }    return true;}int main(){while(~scanf("%d %d",&n,&m)){        if(solve()==false)puts("NO");        for(int i = 1; i <= m; i++)D[i].clear();}return 0;}/*5 21 11 21 11 11 15 21 11 21 11 12 1 2*/


0 0