0
点赞
收藏
分享

微信扫一扫

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\n" ,ans);
}
return 0;
}






举报

相关推荐

0 条评论