您的位置:首页 > 其它

poj 2289 二分+多重匹配

2015-08-23 12:24 447 查看
最大值最小的一个常用方法是二分。二分“the size of the largest group”然后每次判断最大匹配数是否为人数即可。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cctype>
using namespace std;

const int X = 1000;
const int Y = 500;
int head[X];
int cnt[Y];
int mark[Y][X];
bool visit[Y];
int n, m, e, sz;

void init()
{
e = 0;
memset( head, -1, sizeof(head) );
}

struct Edge
{
int v, next;
} edge[X * Y];

void addEdge( int u, int v )
{
edge[e].v = v;
edge[e].next = head[u];
head[u] = e++;
}

int dfs( int u )
{
for ( int i = head[u]; i != -1; i = edge[i].next )
{
int v = edge[i].v;
if ( !visit[v] )
{
visit[v] = 1;
if ( cnt[v] < sz )
{
mark[v][cnt[v]++] = u;
return 1;
}
else
{
for ( int j = 0; j < cnt[v]; j++ )
{
if ( dfs( mark[v][j] ) )
{
mark[v][j] = u;
return 1;
}
}
}
}
}
return 0;
}

bool hungary()
{
memset( cnt, 0, sizeof(cnt) );
for ( int i = 0; i < n; i++ )
{
memset( visit, 0, sizeof(visit) );
if ( !dfs(i) ) return false;
}
return true;
}

const int L = 501;
char list[L];

int main ()
{
while ( scanf("%d%d", &n, &m) != EOF )
{
if ( n == 0 && m == 0 ) break;
init();
getchar();
for ( int i = 0; i < n; i++ )
{
gets(list);
int len = strlen(list);
int j = 0, ret;
while ( 1 )
{
while ( !isdigit(list[j]) ) j++;
ret = 0;
while ( isdigit(list[j]) )
{
ret = ret * 10 + list[j] - '0';
j++;
}
addEdge( i, ret );
if ( j == len ) break;
}
}
int lb = 1, ub = n;
while ( lb < ub )
{
sz = ( lb + ub ) >> 1;
if ( hungary() )
{
ub = sz;
}
else
{
lb = sz + 1;
}
}
printf("%d\n", lb);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: