http://poj.org/problem?id=3041
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 14218 | Accepted: 7736 |
Description
Input
Output
Sample Input
3 4 1 1 1 3 2 2 3 2
Sample Output
2
Hint
在一块N*N的田野中,有伞兵降落,用坐标表示,问每行和每列都有机枪,可以消灭一行和一列的敌人,问最少用多少个机枪能消灭完所有的敌人;
分析;
二分图最少点覆盖:
最小覆盖: 最小覆盖要求用最少的点(X集合或Y集合的都行)让每条边都至少和其中一个点关联。可以证明:最少的点(即覆盖数)=最大匹配数
把行数构成x集合,列数构成y集合,按照坐标连线;
程序;
#include"string.h" #include"stdio.h" #include"iostream" #include"queue" #define M 10009 #define inf 999999999 using namespace std; struct st { int u,v,next; }edge[M]; int head[M],use[M],t,x[M],y[M]; void init() { t=0; memset(head,-1,sizeof(head)); } void add(int u,int v) { edge[t].u=u; edge[t].v=v; edge[t].next=head[u]; head[u]=t++; } int finde(int u) { for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(!use[v]) { use[v]=1; if(!y[v]||finde(y[v])) { use[v]=1; y[v]=u; x[u]=v; return 1; } } } return 0; } int max_match(int n) { int ans=0; memset(x,0,sizeof(x)); memset(y,0,sizeof(y)); for(int i=1;i<=n;i++) { if(!x[i]) { memset(use,0,sizeof(use)); ans+=finde(i); } } return ans; } int main() { int n,m,a,b; while(scanf("%d%d",&n,&m)!=-1) { init(); while(m--) { scanf("%d%d",&a,&b); add(a,n+b); } int ans=max_match(n); printf("%d\n",ans); } return 0; }