加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

POJ PKU 2289 最大流 二分 分组

(2010-08-21 18:46:13)
标签:

poj

pku

2289

最大流

二分

分组

it

分类: 网络流

题目描述:

N个人,分成M组。

给你N个人可以分到组(一个人可以分到多个组,但是最终只能分到一个组)。

问你最大组的人数最少是多少。

解题报告:

源点s和N个人连接,容量1。

i号人可以分到j号组,连接i和j,容量1。

二分每组最大组人数mid。

M个组点,连接汇点t,容量是mid。

求最大流,如果等于总人数,mid合法。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define siz 2005
#define Max 0x7fffffff
struct edge{int from, to, va, next;}e[siz * 1000];
int v[siz], que[siz], dis[siz], cnt, cur[siz];
void insert(int from, int to, int va)
{
    e[cnt].from = from, e[cnt].to = to; e[cnt].va = va;
    e[cnt].next = v[from]; v[from] = cnt++;
    e[cnt].from = to, e[cnt].to = from; e[cnt].va = 0;
    e[cnt].next = v[to]; v[to] = cnt++;
}
bool bfs(int n, int s, int t)
{
    int head, tail, id;
    head = tail = 0; que[tail++] = s;
    fill(dis, dis + n, -1);dis[s] = 0;
    while(head < tail) // bfs,得到顶点i的距s的最短距离dis[i]
        for(id = v[que[head++]]; id != -1; id = e[id].next)
            if (e[id].va > 0 && dis[e[id].to] == -1)
            {
                dis[e[id].to] = dis[e[id].from] + 1;
                que[tail++] = e[id].to;
                if (e[id].to == t) return true;
            }
    return false;
}

int Dinic(int n, int s, int t)
{
    int maxflow = 0, tmp, i;
    while(bfs(n, s, t))
    {
        int u = s, tail = 0;
        for(i = 0; i < n; i++) cur[i] = v[i];
        while(cur[s] != -1)
        {
            if (u != t && cur[u] != -1 && e[cur[u]].va > 0 && dis[u] + 1 == dis[e[cur[u]].to])
            {que[tail++] = cur[u]; u = e[cur[u]].to;}
            else if (u == t)
            {
                for(tmp = Max, i = tail - 1; i >= 0; i--) tmp = min(tmp, e[que[i]].va);
                for(maxflow += tmp, i = tail - 1; i >= 0; i--)
                {
                    e[que[i]].va -= tmp;
                    e[que[i] ^ 1].va += tmp;
                    if (e[que[i]].va == 0) tail = i;
                }
                u = e[que[tail]].from;
            }
            else
            {
                while(tail > 0 && u != s && cur[u] == -1) u = e[que[--tail]].from;
                cur[u] = e[cur[u]].next;
            }
        }
    }
    return maxflow;
}
int n, m, x, s, t, re;
char str[40];
void jeogia()
{
    int l = 1, r = n;
    while(l <= r)
    {
        int mid = (l + r) >> 1;
        for(int i = 0; i < cnt; i++)
            if (i % 2) e[i].va = 0;
            else if (e[i].from >= n && e[i].from < n + m) e[i].va = mid;
            else e[i].va = 1;
        if (Dinic(n + m + 2, s, t) == n)
        {
            if (mid < re) re = mid;
            r = mid - 1;
        }
        else l = mid + 1;
    }
}
int main()
{
    while(scanf("%d%d", &n, &m) && (n || m))
    {
        cnt = 0; memset(v, -1, sizeof(v));
        s = n + m, t = n + m + 1;
        for(int i = 0; i < n; i++)
        {
            scanf("%s", str);
            insert(s, i, 1);
            while(true)
            {
                scanf("%d", &x);
                insert(i, x + n, 1);
                if ((getchar()) == '\n') break;
            }
        }
        for(int i = 0; i < m; i++) insert(i + n, t, 1);
        re = 100000; jeogia();
        printf("%d\n", re);
    }
    return 0;
}

 

 

 

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有