您的位置:首页 > 其它

HDU 4619 —— Warm up 2(二分图最大匹配)

2014-03-07 12:52 585 查看
题目:http://acm.hdu.edu.cn/showproblem.php?pid=4619

最近学了二分匹配,这块我是看kuangbin大神的文章的:/article/4680097.html

个人觉得他博客的文章很赞,很多总结也写得很好,强力推荐!

平面上有很多1X2的多米诺骨牌,横放或竖放,相同方向的不会重叠。现在要取走一些,使得剩下的两两没有重叠,问最多能剩下多少个。

有两种考虑的方法,一种是每块牌看作一个点,有重叠到的两块骨牌之间就连一条线,那么问题就是求最大独立集,最大独立集=总点数-最大匹配。

另一种就是将每个格点(每个骨牌占据两个格点)当作一个点,同一块骨牌覆盖到的格点就连一条线,那么问题就是对这些格点求一个最大匹配。

前者可以看作有N+M个点,后者最多是2*(N+M)个点。

但前者构图的时候每个骨牌都要去遍历另一种骨牌,构图的复杂度是O(NM),这种做法在kuangbin的博客上也有;

后者则只是在读入骨牌的时候直接构图,不用考虑其他骨牌,复杂度是O(N+M),但相对的后期处理的点就比较多,我采用的是这种;

对于每个坐标(x,y),因为0<=x<=100 ,0<=y<=100,所以每个坐标可以映射成一个数z=x*101+y

用一个f[z]来记录这块格点对应的编号,从1开始,因为N和M都不超过1000,所以覆盖到的最多4000个,如果不整理编号总共要101*101个点,但其中很多是空白的。

然后就是构图求最大匹配,最后的答案记得除以2。

二分匹配用的是Hopcroft-Carp算法。

#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
#define pb push_back
#define maxn 4001
const int inf = 0x7fffffff;
inline void IN(int& x){
char c=getchar();
while(c<48 || c>57) c=getchar();
x=0;
while(c>=48 && c<=57){
x=x*10+c-48;
c=getchar();
}
}
vector<int> V[maxn];
int n, dis;
int f[20000];
int dx[maxn], dy[maxn], Mx[maxn],  My[maxn];
bool vis[maxn];
bool search(){
queue<int> Q;
dis=inf;
memset(dx,-1,sizeof(dx));
memset(dy,-1,sizeof(dy));
for(int i=1; i<=n; i++){
if(Mx[i]==-1){
dx[i]=0; Q.push(i);
}
}
while(!Q.empty()){
int u=Q.front(); Q.pop();
if(dx[u]>dis)   break;
for(int i=0; i<V[u].size(); i++){
int j=V[u][i];
if(dy[j]!=-1)   continue;
dy[j] = dx[u]+1;
if(My[j]==-1)   dis=dy[j];
else{
dx[My[j]] = dy[j]+1;
Q.push(My[j]);
}
}
}
return (dis!=inf);
}
bool dfs(int x){
for(int i=0; i<V[x].size(); i++){
int j= V[x][i];
if(vis[j] || dy[j]!=dx[x]+1)  continue;
vis[j]=1;
if(My[j]!=-1 && dy[j]==dis) continue;
if(My[j]==-1 || dfs(My[j])){
My[j]=x; Mx[x]=j;
return 1;
}
}
return 0;
}
int MaxMatch(){
int ans=0;
memset(Mx,-1,sizeof(Mx));
memset(My,-1,sizeof(My));
while(search()){
memset(vis,0,sizeof(vis));
for(int i=1; i<=n; i++){
if(Mx[i]==-1 && dfs(i)) ans++;
}
}
return ans;
}
int main(){
while(1){
int a, b, x, y, z1, z2;
IN(a); IN(b);
if(!(a||b)) break;
memset(f,0,sizeof(f));
n=0;
while(a--){
IN(x); IN(y);
z1 = x*101+y;
z2 = z1+101;
if(!f[z1]){
f[z1]=++n;
V
.clear();
}
z1 = f[z1];
if(!f[z2]){
f[z2]=++n;
V
.clear();
}
z2 = f[z2];
V[z1].pb(z2);
V[z2].pb(z1);
}
while(b--){
IN(x); IN(y);
z1 = x*101+y;
z2 = z1+1;
if(!f[z1]){
f[z1]=++n;
V
.clear();
}
z1 = f[z1];
if(!f[z2]){
f[z2]=++n;
V
.clear();
}
z2 = f[z2];
V[z1].pb(z2);
V[z2].pb(z1);
}
printf("%d\n", MaxMatch()>>1);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: