1、题目类型:图论、最大流、Edmonds_Karp算法。
2、解题思路:(1)根据建立图的连接矩阵,并记录被匹配男生的总数目cnt;(2)判断cnt与男生数目的大小,如果cnt小则表示不可能完成任务,直接 impossible;(3)由最小可能party数目开始遍历,每次女生的输出容量加加,直到Edmonds_Karp寻找最大流等于男生数目即找到了最佳答案,否则impossible。
3、注意事项:注意当cnt不可能满足时,不进入Edmonds_Karp,否则TLE。
4、实现方法:
#include
<
iostream
>
using namespace std;
#define MAXN 180
int m,w,s,t,cnt,ans;
int map[MAXN][MAXN],r[MAXN][MAXN];
int pre[MAXN],d[MAXN];
bool vis[MAXN];
void Init()
{
int i,j,a,b;
cnt = 0 ;
memset(map, 0 , sizeof (map));
memset(vis, 0 , sizeof (vis));
cin >> m >> w;
for (i = 1 ;i <= m;i ++ )
map[ 0 ][i] = 1 ;
for (i = m + 1 ;i <= w + m;i ++ )
{
cin >> a;
for (j = 0 ;j < a;j ++ )
{
cin >> b;
b ++ ;
map[b][i] = 1 ;
if ( ! vis[b])
{
cnt ++ ;
vis[b] = 1 ;
}
}
}
}
// 以下求最短路径增广
bool BFS( int s, int t, int n)
{
int front, rear, u, v;
int Q[MAXN * MAXN];
memset(pre, - 1 , sizeof (pre));
front = rear = 0 ;
Q[rear ++ ] = s;
d[s] = 0 ;
while (front < rear)
{
u = Q[front ++ ];
for (v = 0 ; v < n; v ++ )
{
if (pre[v] == - 1 && r[u][v] > 0 )
{
pre[v] = u;
d[u] = d[v] + 1 ;
Q[rear ++ ] = v;
if (v == t) return true ;
}
}
}
return false ;
}
int Edmonds_Karp( int s, int t, int n)
{
int u, v, inc, maxflow = 0 ;
while ( true )
{
// 终点不在剩余网络中
if ( ! BFS(s, t, n)) break ;
inc = 10000000 ;
// 以下求增广的流量
for (v = t; v != s; v = u)
{
u = pre[v];
if (r[u][v] < inc) inc = r[u][v];
}
// 以下重建剩余网络
for (v = t; v != s; v = u)
{
u = pre[v];
r[u][v] -= inc;
r[v][u] += inc;
}
// 增加流量
maxflow += inc;
}
return maxflow;
}
void Solve()
{
int flag = 0 ;
ans = m / w;
s = 0 ;
t = w + m + 1 ;
for ( int i = ans;i <= m;i ++ )
{
for ( int j = m + 1 ;j <= w + m;j ++ )
map[j][t] = i;
memcpy(r,map, sizeof (map));
if (Edmonds_Karp(s,t,t + 1 ) == m)
{
cout << i << endl;
flag = 1 ;
break ;
}
}
if ( ! flag)
cout << " impossible " << endl;
}
int main()
{
int T;
cin >> T;
while (T -- )
{
Init();
if (cnt < m)
cout << " impossible " << endl;
else
Solve();
}
return 0 ;
}
using namespace std;
#define MAXN 180
int m,w,s,t,cnt,ans;
int map[MAXN][MAXN],r[MAXN][MAXN];
int pre[MAXN],d[MAXN];
bool vis[MAXN];
void Init()
{
int i,j,a,b;
cnt = 0 ;
memset(map, 0 , sizeof (map));
memset(vis, 0 , sizeof (vis));
cin >> m >> w;
for (i = 1 ;i <= m;i ++ )
map[ 0 ][i] = 1 ;
for (i = m + 1 ;i <= w + m;i ++ )
{
cin >> a;
for (j = 0 ;j < a;j ++ )
{
cin >> b;
b ++ ;
map[b][i] = 1 ;
if ( ! vis[b])
{
cnt ++ ;
vis[b] = 1 ;
}
}
}
}
// 以下求最短路径增广
bool BFS( int s, int t, int n)
{
int front, rear, u, v;
int Q[MAXN * MAXN];
memset(pre, - 1 , sizeof (pre));
front = rear = 0 ;
Q[rear ++ ] = s;
d[s] = 0 ;
while (front < rear)
{
u = Q[front ++ ];
for (v = 0 ; v < n; v ++ )
{
if (pre[v] == - 1 && r[u][v] > 0 )
{
pre[v] = u;
d[u] = d[v] + 1 ;
Q[rear ++ ] = v;
if (v == t) return true ;
}
}
}
return false ;
}
int Edmonds_Karp( int s, int t, int n)
{
int u, v, inc, maxflow = 0 ;
while ( true )
{
// 终点不在剩余网络中
if ( ! BFS(s, t, n)) break ;
inc = 10000000 ;
// 以下求增广的流量
for (v = t; v != s; v = u)
{
u = pre[v];
if (r[u][v] < inc) inc = r[u][v];
}
// 以下重建剩余网络
for (v = t; v != s; v = u)
{
u = pre[v];
r[u][v] -= inc;
r[v][u] += inc;
}
// 增加流量
maxflow += inc;
}
return maxflow;
}
void Solve()
{
int flag = 0 ;
ans = m / w;
s = 0 ;
t = w + m + 1 ;
for ( int i = ans;i <= m;i ++ )
{
for ( int j = m + 1 ;j <= w + m;j ++ )
map[j][t] = i;
memcpy(r,map, sizeof (map));
if (Edmonds_Karp(s,t,t + 1 ) == m)
{
cout << i << endl;
flag = 1 ;
break ;
}
}
if ( ! flag)
cout << " impossible " << endl;
}
int main()
{
int T;
cin >> T;
while (T -- )
{
Init();
if (cnt < m)
cout << " impossible " << endl;
else
Solve();
}
return 0 ;
}