PS:题目是中文的就不再翻译了。
思路:
求最大可以放的‘车’数目:将行与列分成两个集合,每行/列都作为1个集合中的点,题目所给的行与列的交点当作边。直接二分图匹配即可。
求‘重要’的顶点个数:枚举每个顶点(二分图中的边);将他们去掉后,再重新进行一次匹配。如果匹配数减少,则说明该顶点是一个‘重要’的点。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
#define N 350
#define INF 0x3f3f3f3f
struct node
{
int v, next;
}a[N*N];
int head[N], used[N], girl[N];
int n, m, k, cnt, t = 0;
void add(int u, int v)
{
a[cnt].v = v;
a[cnt].next = head[u];
head[u] = cnt++;
}
int find(int x, int d)
{
int i;
for(i = head[x]; i != -1; i = a[i].next)
{
if(d == -1 || i != d)
{
int v = a[i].v;
if(used[v] == -1)
{
used[v] = 1;
if(girl[v] == -1 || find(girl[v], d))
{
girl[v] = x;
return 1;
}
}
}
}
return 0;
}
int main()
{
while(scanf("%d%d%d", &n, &m, &k) != EOF)
{
int i, j;
int u, v, con = 0;
cnt = 0;
memset(head, -1, sizeof(head));
for(i = 1; i <= k; i++)
{
scanf("%d%d", &u, &v);
add(u, v);
}
int ans = 0;
memset(girl, -1, sizeof(girl));
for(i = 1; i <= n; i++)
{
memset(used, -1, sizeof(used));
if(find(i, -1))
ans++;
}
for(i = 0; i < cnt; i++)
{
int res = 0;
memset(girl, -1, sizeof(girl));
for(j = 1; j <= n; j++)
{
memset(used, -1, sizeof(used));
if(find(j, i))
res++;
}
if(res != ans)
con++;
}
printf("Board %d have %d important blanks for %d chessmen.\n", ++t, con, ans);
}
return 0;
}