POJ 2289 Jamie's Contact Groups (二分答案+匹配流)

题意:Jamie有很多联系人,但是很不方便管理,他想把这些联系人分成组,已知这些联系人可以被分到哪个组中去,而且要求每个组的联系人上限最小,即有一整数k,使每个组的联系人数都不大于k,问这个k最小是多少?

思路:这个题很像以前的那个星际战舰的那个题,一般就是二分答案,对每一个值进行建图,求最大流,查看这个最大流是否等于总人数,虽然比较繁琐,但是思路还是很清晰的,之后就是SAP模板了......(每次建图的时候一定要对信息进行初始化啊!!!WA了N次!)

  
    
#include < iostream >
#include
< cstdio >
#include
< algorithm >
#include
< memory.h >
#include
< cmath >
#include
< bitset >
#include
< queue >
#include
< vector >
using namespace std;

const int BORDER = ( 1 << 20 ) - 1 ;
const int MAXSIZE = 37 ;
const int MAXN = 1508 ;
const int INF = INT_MAX;

#define CLR(x,y) memset(x,y,sizeof(x))
#define ADD(x) x=((x+1)&BORDER)
#define IN(x) scanf("%d",&x)
#define OUT(x) printf("%d\n",x)
#define MIN(m,v) (m)<(v)?(m):(v)
#define MAX(m,v) (m)>(v)?(m):(v)
#define ABS(x) ((x)>0?(x):-(x))

int index,n,m,ans;
int adj[MAXN][MAXN], in [MAXN];
int nv,s,t;
int net[MAXN];
char str[ 20 ];

struct Edge{
int next,pair;
int v,cap,flow;
}edge[
1500000 ];


int init()
{
index
= 0 ;
CLR(net,
- 1 );
CLR(adj,
0 );
CLR(
in , 0 );
ans
= 0 ;
return 0 ;
}
int input()
{
int i,j,tmp;
char ch;
getchar();
for (i = 1 ;i <= n; i ++ )
{
ch
= getchar();
while ((ch >= ' a ' && ch <= ' z ' ) || (ch >= ' A ' && ch <= ' Z ' ))
ch
= getchar();
while (ch == ' ' )
ch
= getchar();
while ( true )
{
j
= 0 ;
while (ch >= ' 0 ' && ch <= ' 9 ' )
{
j
= j * 10 + ch - ' 0 ' ;
ch
= getchar();
}
adj[i][j
+ 1 ] = 1 ;
in [j + 1 ] ++ ;
if (ch == ' \n ' ) break ;
while (ch == ' ' ) ch = getchar();
}
}
s
= 0 ;
nv
= n + m + 2 ;
t
= nv - 1 ;
return 1 ;
}

void add_edge( const int & u, const int & v, const int & val)
{
edge[index].next
= net[u];
net[u]
= index;
edge[index].v
= v;
edge[index].cap
= val;
edge[index].flow
= 0 ;
edge[index].pair
= index + 1 ;
++ index;
edge[index].next
= net[v];
net[v]
= index;
edge[index].v
= u;
edge[index].cap
= 0 ;
edge[index].flow
= 0 ;
edge[index].pair
= index - 1 ;
++ index;
}
int make_graph( const int & limit)
{
int i,j,tmp,k,u,v,val;
CLR(net,
- 1 );
index
= 0 ;
for (i = 1 ; i <= n; ++ i)
add_edge(s,i,
1 );
for (i = 1 ; i <= n; ++ i)
{
for (j = 1 ; j <= m; ++ j)
if (adj[i][j])
add_edge(i,j
+ n, 1 );
}
for (i = 1 ; i <= m; ++ i)
if ( in [i] >= limit)
add_edge(i
+ n,t,limit);
else
add_edge(i
+ n,t, in [i]);
return 0 ;
}
int ISAP()
{
long numb[MAXN],dist[MAXN],curedge[MAXN],pre[MAXN];
long cur_flow,max_flow,u,tmp,neck,i;
memset(dist,
0 , sizeof (dist));
memset(numb,
0 , sizeof (numb));
for (i = 1 ; i <= nv ; ++ i)
curedge[i]
= net[i];
numb[nv]
= nv;
max_flow
= 0 ;
u
= s;
while (dist[s] < nv)
{
/* first , check if has augmemt flow */
if (u == t)
{
cur_flow
= INF;
for (i = s; i != t;i = edge[curedge[i]].v)
{
if (cur_flow > edge[curedge[i]].cap)
{
neck
= i;
cur_flow
= edge[curedge[i]].cap;
}
}
for (i = s; i != t; i = edge[curedge[i]].v)
{
tmp
= curedge[i];
edge[tmp].cap
-= cur_flow;
edge[tmp].flow
+= cur_flow;
tmp
= edge[tmp].pair;
edge[tmp].cap
+= cur_flow;
edge[tmp].flow
-= cur_flow;
}

max_flow
+= cur_flow;
u
= s;
}
/* if .... else ... */
for (i = curedge[u]; i != - 1 ; i = edge[i].next)
if (edge[i].cap > 0 && dist[u] == dist[edge[i].v] + 1 )
break ;
if (i != - 1 )
{
curedge[u]
= i;
pre[edge[i].v]
= u;
u
= edge[i].v;
}
else {
if ( 0 == -- numb[dist[u]]) break ;
curedge[u]
= net[u];
for (tmp = nv,i = net[u]; i != - 1 ; i = edge[i].next)
if (edge[i].cap > 0 )
tmp
= tmp < dist[edge[i].v] ? tmp:dist[edge[i].v];
dist[u]
= tmp + 1 ;
++ numb[dist[u]];
if (u != s) u = pre[u];
}
}
return max_flow;
}
int work()
{
int low,high,mid,tmp;
int pre;
low
= 0 ;
high
= - 1 ;
for ( int i = 1 ; i <= m; ++ i)
high
= MAX(high, in [i]);
while (low <= high)
{
mid
= (low + high) >> 1 ;
make_graph(mid);
tmp
= ISAP();
if (tmp == n)
{
pre
= mid;
high
= mid - 1 ;
}
else
low
= mid + 1 ;
}
printf(
" %d\n " ,pre);
return 0 ;
}
int main()
{
while (scanf( " %d%d " , & n, & m) != EOF)
{
if ( ! n && ! m)
break ;
init();
input();
work();
}
return 0 ;
}

 

你可能感兴趣的:(group)