zoukankan      html  css  js  c++  java
  • 1669 DINIC+二分

    题意:
          给你一些名单,和每个名单可以放在哪个分组里,现在要求你把所有的人都分到一个他属于的分组(之一),然后问你分组中最多的那个人数最少是多少...


    思路:
         二分最多的最少,然后用最大流去判断分组是否合理,建图如下
             
        s 到 所有人连一条边 流量是1
        所有分组 到 t 连一条边,流量是mid
        然后把所有人和自己属于的分组连边,流量1
        
        跑一边最大流,如果答案等于 N(人数) 那么当前二分满足

        up = mid - 1 ........


    #include<stdio.h>
    #include<string.h>
    #include<queue>
    
    #define N_node 1500 + 50
    #define N_edge 2000000 + 10000
    #define INF 1000000000
    
    using namespace std;
    
    typedef struct
    {
       int to ,next ,cost;
    }STAR;
    
    typedef struct
    {
       int x ,t;
    }DEP;
    
    typedef struct
    {
       int a ,b;
    }EDGE;
    
    STAR E[N_edge];
    DEP xin ,tou;
    EDGE edge[N_edge];
    int list[N_node] ,tot;
    int list1[N_node];
    int deep[N_node];
    char str[1000000];
    
    void add(int a ,int b ,int c)
    {
       E[++tot].to = b;
       E[tot].cost = c;
       E[tot].next = list[a];
       list[a] = tot;
       
       E[++tot].to = a;
       E[tot].cost = 0;
       E[tot].next = list[b];
       list[b] = tot;
    }
    
    int minn(int x ,int y)
    {
       return x < y ? x : y;
    }
    
    bool BFS_deep(int s ,int t ,int n)
    {
       memset(deep ,255 ,sizeof(deep));
       xin.x = s;
       xin.t = 0;
       deep[s] = 0;
       queue<DEP>q;
       q.push(xin);
       while(!q.empty())
       {
          tou = q.front();
          q.pop();
          for(int k = list[tou.x] ;k ;k = E[k].next)
          {
             xin.x = E[k].to;
             xin.t = tou.t + 1;
             if(!E[k].cost || deep[xin.x] != -1)
             continue;
             deep[xin.x] = xin.t;
             q.push(xin);
          }
       }
       for(int i = 0 ;i <= n ;i ++)
       list1[i] = list[i];
       return deep[t] != -1;
    }
    
    
    int DFS_flow(int s ,int t ,int flow)
    {
       if(s == t) return flow;
       int nowflow = 0;
       for(int k = list1[s] ;k ;k = E[k].next)
       {
          list1[s] = k;
          int to = E[k].to;
          int c  = E[k].cost;
          if(deep[to] != deep[s] + 1 || ! E[k].cost)
          continue;
          int tmp = DFS_flow(to ,t ,minn(c ,flow - nowflow));
          nowflow += tmp;
          E[k].cost -= tmp;
          E[k^1].cost += tmp;
          if(nowflow == flow) break;
       }
       if(!nowflow) deep[s] = 0;
       return nowflow;
    }
    
    int DINIC(int s ,int t ,int n)
    {
       int ans = 0;
       while(BFS_deep(s ,t ,n))
       {
          ans += DFS_flow(s ,t ,INF);
       }
       return ans;
    }
    
    bool ok(int mid ,int tt ,int n ,int m)
    {
       memset(list ,0 ,sizeof(list));
       tot = 1;
       int i;
       for(i = 1 ;i <= n ;i ++)
       add(0 ,i ,1);
       for(i = 1 ;i <= m ;i ++)
       add(n + i ,n + m + 1 ,mid);
       for(i = 1 ;i <= tt ;i ++)
       add(edge[i].a ,edge[i].b + n ,1);
       return DINIC(0 ,n + m + 1 ,n + m + 1) == n;
    }
       
       
       
       
       
    
    int main ()
    {
       int n ,m ,i ,j;
       while(~scanf("%d %d" ,&n ,&m) && n + m)
       {
          getchar();
          int tt = 0;
          for(i = 1 ;i <= n ;i ++)
          {
             gets(str);
             int l = strlen(str) - 1;
             j = 0;
             while(str[j] != ' ')
             j++;
             int num = 0;
             for(j++ ;j <= l ;j ++)
             {
                if(str[j] == ' ')
                {
                   edge[++tt].a = i;
                   edge[tt].b = num + 1;
                   num = 0;
                   continue;
                }
                num = num * 10 + str[j] - 48;
             }
             edge[++tt].a = i;
             edge[tt].b = num + 1;
          }
          
          int low ,up ,mid;
          low = 0 ,up = n;
          int ans;
          while(low <= up)
          {
             mid = (low + up) >> 1;
             if(ok(mid ,tt ,n ,m))
             {
                ans = mid;
                up = mid - 1;
             }
             else
             low = mid + 1;
          }
          printf("%d
    " ,ans);
       }
       return 0;
    }
           
    



  • 相关阅读:
    树状数组基本操作
    P1802 5倍经验日 题解
    函数学习总结
    康托展开
    中国电信CDMA无线上网卡短信收发
    报错:无法获取实体类XXX对应的表名!
    javajvisualvm远程监控云服务器上的Tomcat8.5
    服务器防火墙开放端口
    报错:列"AGENT_ENTITY_NAME"的值太大(实际值: 60,最大值50) oracle VARCHAR2和NVARCHAR2的区别
    linux中查看端口是否被占用lsof i:port
  • 原文地址:https://www.cnblogs.com/csnd/p/12063186.html
Copyright © 2011-2022 走看看