http://acm.hdu.edu.cn/showproblem.php?pid=4619
当时我不会匈牙利,我的傻X队友不会建图,当时没做出,现在会了匈牙利,这题就成了水题。
15ms AC
首先明确理解二分图匹配:
给定一个二分图G,在G的一个子图M中,M的边集中的任意两条边都不依附于同一个顶点,则称M是一个匹配.
选择这样的边数最大的子集称为图的最大匹配问题(maximal matching problem)
这样思考:水平的骨牌与竖直的骨牌有重合,现在要消除重合,所谓消除重合,就是两个有重合的只取一个。
把水平的骨牌当做点集A中的点,竖直的骨牌当做点集B中的点,A 和B 有重合的建立边,则边的 两个顶点只要一个。然后骨牌个数之和-匹配数就是Ans
好像还是解释的不清...以后再来修改吧
下面贴代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 1100
int mat[N][N];
int cx[N],cy[N];
bool vis[N];
int n,m;
struct node{
int x,y;
};
node x[N],y[N];
int path(int u)
{
int v;
for(v=0;v<m;v++)
{
if(mat[u][v]&&!vis[v])
{
vis[v]=1;
if(cy[v]==-1||path(cy[v]))
{
cx[u]=v;
cy[v]=u;
return 1;
}
}
}
return 0;
}
int maxmatch()
{
int i,res=0;
memset(cx,-1,sizeof(cx));
memset(cy,-1,sizeof(cy));
for(i=0;i<n;i++)
if(cx[i]==-1)
{
memset(vis,0,sizeof(vis));
res+=path(i);
}
return res;
}
int main()
{
//freopen("hdu 4619.txt","r",stdin);
int i,j,xx,yy;
while(scanf("%d%d",&n,&m),n+m)
{
for(i=0;i<n;i++)
scanf("%d%d",&x[i].x,&x[i].y);
for(i=0;i<m;i++)
scanf("%d%d",&y[i].x,&y[i].y);
/*建图*/
memset(mat,0,sizeof(mat));
for(i=0;i<n;i++)
{
xx=x[i].x;
yy=x[i].y;
for(j=0;j<m;j++)
{
/*这里y[j].y我写成y[i].y 一直Wa Wa了几个小时啊........*/
if((xx==y[j].x&&yy==y[j].y)||((xx+1)==y[j].x&&yy==y[j].y)||(xx==y[j].x&&yy==(y[j].y+1))||((xx+1)==y[j].x&&yy==(y[j].y+1)))mat[i][j]=1;
}
}
printf("%d\n",m+n-maxmatch());
}
return 0;
}