您的位置:首页 > 其它

poj 1698 二分图多重匹配

2015-08-22 20:14 393 查看
网络流解法:

容易想到将每一天看做一个点并和汇点连容量为1的边(因为一天只能做一件事情),每个电影看做一个点并和源点连容量为d的边(即几天可以完成),然后电影和对应天数连容量为1的边,求最大流判断是否满流即可。

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

const int INF = 9999999;
const int N = 400;
const int M = 20000;
int head
;
int level
;
int q
;
int n, e, front, rear;

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

struct Edge
{
int v, next, cap;
} edge[M];

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

bool bfs( int s, int t )
{
front = rear = 0;
memset( level, -1, sizeof(level) );
q[rear++] = s;
level[s] = 0;
while ( front < rear )
{
int u = q[front++];
for ( int i = head[u]; i != -1; i = edge[i].next )
{
int v = edge[i].v, cap = edge[i].cap;
if ( level[v] == -1 && cap > 0 )
{
level[v] = level[u] + 1;
q[rear++] = v;
}
}
}
return level[t] != -1;
}

int dfs( int u, int sum, int t )
{
if ( u == t ) return sum;
int os = 0;
for ( int i = head[u]; i != -1; i = edge[i].next )
{
int v = edge[i].v, cap = edge[i].cap;
if ( level[v] == level[u] + 1 && cap > 0 )
{
int tt = dfs( v, min( sum, cap ), t );
if ( tt == 0 ) continue;
edge[i].cap -= tt;
edge[i ^ 1].cap += tt;
sum -= tt;
os += tt;
if ( sum == 0 ) break;
}
}
if ( os == 0 ) level[u] = -1;
return os;
}

int dinic( int s, int t )
{
int res = 0;
while ( bfs( s, t ) )
{
res += dfs( s, INF, t );
}
return res;
}

const int D = 7;
int nn[D];

int main ()
{
int _case;
scanf("%d", &_case);
while ( _case-- )
{
scanf("%d", &n);
init();
int tot = 0, wmax = -1, d, w;
for ( int i = 1; i <= n; i++ )
{
for ( int j = 0; j < D; j++ )
{
scanf("%d", nn + j);
}
scanf("%d%d", &d, &w);
tot += d;
wmax = max( wmax, w );
addEdge( 0, i, d );
for ( int j = 0; j < D; j++ )
{
if ( nn[j] == 1 )
{
for ( int k = 0; k < w; k++ )
{
int num = n + k * 7 + j + 1;
addEdge( i, num, 1 );
}
}
}
}
int tid = n + wmax * 7 + 1;
for ( int i = n + 1; i < tid; i++ )
{
addEdge( i, tid, 1 );
}
if ( dinic( 0, tid ) == tot )
{
puts("Yes");
}
else
{
puts("No");
}
}
return 0;
}


匈牙利解法(些许改变):

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

const int X = 350;
const int Y = 20;
int head[X];
int sz[Y];
bool visit[Y];
vector<int> mark[Y];
int e;

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 ( mark[v].size() < sz[v] )
{
mark[v].push_back(u);
return 1;
}
else
{
for ( int j = 0; j < mark[v].size(); j++ )
{
if ( dfs( mark[v][j] ) )
{
mark[v][j] = u;
return 1;
}
}
}
}
}
return 0;
}

const int D = 7;
int nn[D];

int main ()
{
int _case;
scanf("%d", &_case);
while ( _case-- )
{
int n;
scanf("%d", &n);
init();
int tot = 0, wmax = -1, d, w;
for ( int i = 0; i < n; i++ )
{
for ( int j = 0; j < D; j++ )
{
scanf("%d", nn + j);
}
scanf("%d%d", &d, &w);
sz[i] = d;
tot += d;
wmax = max( wmax, w );
for ( int j = 0; j < D; j++ )
{
if ( nn[j] == 1 )
{
for ( int k = 0; k < w; k++ )
{
int num = k * 7 + j;
addEdge( num, i );
}
}
}
}
for ( int i = 0; i < n; i++ )
{
mark[i].clear();
}
int res = 0;
for ( int i = 0; i < 7 * wmax; i++ )
{
memset( visit, 0, sizeof(visit) );
res += dfs(i);
}
if ( res == tot )
{
puts("Yes");
}
else
{
puts("No");
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: