zoukankan      html  css  js  c++  java
  • poj 2289 Jamie's Contact Groups【二分+最大流】【二分图多重匹配问题】

    Jamie's Contact Groups
    Time Limit: 7000MS   Memory Limit: 65536K
    Total Submissions: 8473   Accepted: 2875

    Description

    Jamie is a very popular girl and has quite a lot of friends, so she always keeps a very long contact list in her cell phone. The contact list has become so long that it often takes a long time for her to browse through the whole list to find a friend's number. As Jamie's best friend and a programming genius, you suggest that she group the contact list and minimize the size of the largest group, so that it will be easier for her to search for a friend's number among the groups. Jamie takes your advice and gives you her entire contact list containing her friends' names, the number of groups she wishes to have and what groups every friend could belong to. Your task is to write a program that takes the list and organizes it into groups such that each friend appears in only one of those groups and the size of the largest group is minimized.

    Input

    There will be at most 20 test cases. Ease case starts with a line containing two integers N and M. where N is the length of the contact list and M is the number of groups. N lines then follow. Each line contains a friend's name and the groups the friend could belong to. You can assume N is no more than 1000 and M is no more than 500. The names will contain alphabet letters only and will be no longer than 15 characters. No two friends have the same name. The group label is an integer between 0 and M - 1. After the last test case, there is a single line `0 0' that terminates the input.

    Output

    For each test case, output a line containing a single integer, the size of the largest contact group.

    Sample Input

    3 2
    John 0 1
    Rose 1
    Mary 1
    5 4
    ACM 1 2 3
    ICPC 0 1
    Asian 0 2 3
    Regional 1 2
    ShangHai 0 2
    0 0
    

    Sample Output

    2
    2

    Source

    题意:
      N个人,M个组,给出每个人可以考虑选择的组号,要求每个人都必须选且只能选一个组,求一个划分方案使得最多人数的组的人数 是所有方案中人数最少的,结果输出这个最小值。

    题解:

      一对多的二分图多重匹配问题。网络流建图:源点到每个人连边,边权为1;每个人到可以考虑选择的组连边,边权为1;每个组到汇点连边,边权为求解的最小值。这个最小值很明显可以想到二分求解。

    代码:

      1 #include <cstdio>
      2 #include <vector>
      3 #include <algorithm>
      4 #include <queue>
      5 #include <cstring>
      6 using namespace std;
      7 const int N = 2000;
      8 const int M = 1e6;
      9 const int inf = 1e9;
     10 int n, m, S, T;
     11 int dep[N], cur[N];
     12 int head[N];
     13 struct Edge{
     14     int v, c, nex;
     15     Edge(int _v=0,int _c=0,int _nex=0):v(_v),c(_c),nex(_nex){}
     16 }E[M];
     17 
     18 int cnt;
     19 void add(int u, int v, int c){
     20     E[cnt].v = v;
     21     E[cnt].c = c;
     22     E[cnt].nex = head[u];
     23     head[u] = cnt++;
     24 }
     25 
     26 bool bfs() {
     27     queue<int> q;
     28     memset(dep, -1, sizeof(dep));
     29     q.push(S); dep[S] = 0;
     30     while(!q.empty()) {
     31         int u = q.front(); q.pop();
     32         for(int i = head[u]; ~i; i = E[i].nex) {
     33             int v = E[i].v;
     34             if(E[i].c && dep[v] == -1) {
     35                 dep[v] = dep[u] + 1;
     36                 q.push(v);
     37             }
     38         }
     39     }
     40     return dep[T] != -1;
     41 }
     42 int dfs(int u, int flow) {
     43     if(u == T) return flow;
     44     int w, used=0;
     45     for(int i = head[u]; ~i; i = E[i].nex) {
     46         int v = E[i].v;
     47         if(dep[v] == dep[u] + 1) {
     48             w = flow - used;
     49             w = dfs(v, min(w, E[i].c));
     50             E[i].c -= w;  E[i^1].c += w;
     51             if(v) cur[u] = i;
     52             used += w;
     53             if(used == flow) return flow;
     54         }
     55     }
     56     if(!used) dep[u] = -1;
     57     return used;
     58 }
     59 int dinic() {
     60     int ans = 0;
     61     while(bfs()) {
     62         for(int i = 0; i <= T;i++)
     63             cur[i] = head[i];
     64         ans += dfs(S, inf);
     65     }
     66     return ans;
     67 }
     68 int main() {
     69     char s[16];
     70     int i, j, x, t;
     71     while(~scanf("%d%d", &n, &m),n+m) {
     72         memset(head, -1, sizeof(head));
     73         cnt = 0;
     74         S = n+m+1; T = n+m+2;
     75         vector<int>g[N];
     76         for(i = 0; i <= n; ++i) g[i].clear();
     77         for(i = 0; i < n; ++i) {
     78             scanf("%s", s);
     79             while(getchar() != '
    ') {
     80                 scanf("%d", &x);
     81                 g[i].push_back(x);
     82             }
     83         }
     84         int l = 0, r = n, mid;
     85         while(l <= r) {
     86             memset(head, -1, sizeof(head));
     87             cnt = 0;
     88             mid = (l+r)/2;
     89             for(i = 0; i < n; ++i) {
     90                 for(j = 0; j < g[i].size(); ++j)
     91                     add(i, n+g[i][j], 1),add(n+g[i][j], i, 0);
     92             }
     93             for(i = 0; i < n; ++i) add(S,i,1), add(i,S,0);
     94             for(i = n; i < n+m; ++i) add(i,T,mid),add(T,i,0);
     95             t = dinic();
     96             if(t == n) r = mid - 1;
     97             else l = mid + 1;
     98         }
     99         printf("%d
    ", l);
    100     }
    101 }
    485ms
  • 相关阅读:
    教大家如何在word 2007中同时打出对齐上下标以及字母头上有波浪线(非编辑器)
    C#返回多个参数 ref及out
    回溯法解决0-1背包问题
    USB peripherals can turn against their users
    50元制作PS2键盘无线监控装置
    物联网安全拔“牙”实战——低功耗蓝牙(BLE)初探
    Bluetooth Low Energy 嗅探
    MagSpoof:能预测并窃取你下一张信用卡号码的廉价设备
    Python 安全类目推荐 (持续更新)
    树莓派安装kali后的简单配置
  • 原文地址:https://www.cnblogs.com/GraceSkyer/p/9006015.html
Copyright © 2011-2022 走看看