题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4619
题意:给一些水平和竖直放置的牌,相同方向上的不会重叠,但是水平和竖直的可能重叠,问:最少拿走几块能使没有重叠的(输出是最大剩余几块)?
思路:当时没有想到二分匹配,但是由于分两种牌,建图就这样建了:如果两个牌重叠,那么添加一条边,再加上源点、汇点,跑一下网络流,就好了,流量都是1。理由是如果a->b那么别的点就不可能通过源点流到汇点,含义就是把b拿掉了,就不与其他重叠了,所以这样算就是答案。。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn = 3000;
const int maxm = 200000;
const int INF = 0x7FFFFFF;
struct Side{
int to,next,c;
}side[maxm];
int top,node[maxn];
void add_side(int u,int v,int c,int rc){
side[top]=(Side){v,node[u],c};
node[u]=top++;
side[top]=(Side){u,node[v],rc};
node[v]=top++;
}
int start,end,cnt,dis[maxn],gap[maxn];
int get_flow(int u,int flow){
//printf("%d %d\n",u,flow);
if(u==end)return flow;
int ans=0;
for(int i=node[u];i!=-1;i=side[i].next){
int v=side[i].to,c=side[i].c;
if(dis[u]>dis[v]&&c){
int f=get_flow(v,min(flow-ans,c));
ans+=f;
side[i].c-=f;
side[i^1].c+=f;
if(ans==flow)return ans;
}
}
if(!(--gap[dis[u]]))dis[start]=cnt+2;
gap[++dis[u]]++;
return ans;
}
struct H{int x, y;}hh[1100];
struct V{int x, y;}vv[1100];
int jiao(H a,V b){
if(a.x==b.x&&a.y==b.y)return true;
if(a.x==b.x&&a.y==b.y+1)return true;
if(a.y==b.y&&a.x+1==b.x)return true;
if(a.y==b.y+1&&a.x+1==b.x)return true;
return false;
}
int main(){
int n,m;
while(~scanf("%d%d",&n,&m),n+m){
top=0;
memset(node,-1,sizeof(node));
memset(gap,0,sizeof(gap));
memset(dis,0,sizeof(dis));
for(int i=0;i<n;i++)
scanf("%d%d",&hh[i].x,&hh[i].y);
for(int i=0;i<m;i++)
scanf("%d%d",&vv[i].x,&vv[i].y);
for(int i=0;i<n;i++)
add_side(0,i+1,1,0);
for(int i=0;i<m;i++)
add_side(i+1+n,n+m+1,1,0);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(jiao(hh[i],vv[j]))add_side(i+1,j+n+1,1,0);
int ans=0;
start=0;
end=n+m+1;
cnt=n+m+2;
gap[0]=cnt;
while(dis[start]<cnt){
ans+=get_flow(start,INF);
}
printf("%d\n",n+m-ans);
}
}
坑爹的王尼玛 ~ ~