题意:棋盘上有很多点,问最少设置几个棋子可以把这些点都吃掉,还问哪些棋子放置的位置是固定的,不然有些点就不能被吃掉
关键匹配:
先找到最大匹配。
然后对每个匹配边的两个端点u,v查看是否对应唯一的匹配边,
不优化会超时的。看了别人的代码才发现可以这样优化。太神奇了
其中有两处优化
#include "stdio.h"
#include "string.h"
#include "queue"
#include "vector"
#include "algorithm"
using namespace std;
const int maxn = 10005;
const int inf = 1<<30;
int n,m,k,st,ed;
vector<int>map[maxn],map1[maxn];
int cx[maxn],cy[maxn],Cx[maxn];
bool vis[maxn];
bool FindPath( int u )
{
for( int i = 0; i < map[u].size(); i ++ )
{
int v = map[u][i];
if( vis[v] ) continue;
if( st == u && ed == v ) continue;
vis[v] = 1;
if( cy[v] == -1 || FindPath( cy[v] ) )
{
cx[u] = v;
cy[v] = u;
return true;
}
}
return false;
}
bool FindPathY( int v )
{
for( int i = 0; i < map1[v].size(); i ++ )
{
int u = map1[v][i];
if( vis[u] ) continue;
if( st == u && ed == v ) continue;
vis[u] = 1;
if( cx[u] == -1 || FindPathY( cx[u] ) )
{
cx[u] = v;
cy[v] = u;
return true;
}
}
return false;
}
int MaxMatch() //二分图匹配
{
int ans = 0;
memset( cx,-1,sizeof(cx) );
memset( cy,-1,sizeof(cy) );
for( int i = 1; i <= n; i ++ ) //优化,枚举每条边,查看是否可以找到匹配边
{
if( cx[i] == -1 )
{
for( int j = 0; j < map[i].size() && cx[i] == -1; j ++ )
{
int v = map[i][j];
if( cy[v] == -1 )
{
cy[v] = i;
cx[i] = v;
ans ++;
}
}
}
}
for( int i = 1; i <= n; i ++ ) //寻找增广路,增加匹配边
{
if( cx[i] == -1 )
{
memset( vis,0,sizeof(vis) );
ans += FindPath( i );
}
}
return ans;
}
int fun()
{
int ans = 0,flag;
for( int i = 1; i <= n; i ++ ) Cx[i] = cx[i];
for( int i = 1; i <= n; i ++ )
{
if( Cx[i] != -1 )
{
flag = 0; //查看一条边的两个端点是否都没有增广路 等0即为关键点
st = i; ed = cx[i];
cx[st] = cy[ed] = -1;
memset( vis,0,sizeof(vis) );
if( FindPath( st ) ) flag = 1; //判断左端点能否匹配其他点
else
{
memset( vis,0,sizeof(vis) );
if( FindPathY( ed ) ) flag = 1; //判断右端点能否匹配其他点
}
if( !flag )
{
cx[st] = ed;
cy[ed] = st;
ans ++;
}
else
for( int j = i; j <= n; j ++ )
if( cx[j] != Cx[j] )
Cx[j] = -1;
//如果在寻找增广路时,匹配边上的点发生变化,说明表示关键匹配,
//下次无需再进行判断了
}
}
return ans;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("data.txt","r",stdin);
#endif
int x,y,cas = 1;
while( scanf("%d%d%d",&n,&m,&k)!=EOF )
{
for( int i = 1; i <= n; i ++ ) map[i].clear();
for( int i = 1; i <= m; i ++ ) map1[i].clear();
for( int i = 0; i < k; i ++ )
{
scanf("%d%d",&x,&y);
map[x].push_back( y );
map1[y].push_back( x );
}
st = ed = -1;
int cur = MaxMatch();
int cnt = fun();
printf("Board %d have %d important blanks for %d chessmen.\n",cas ++,cnt,cur);
}
return 0;
}