poj 3041 最小点覆盖,二分图匹配,匈牙利算法

/*

  http://poj.org/problem?id=3041

  一个N*N的表格,表格中有一些asteroid,weapon 每次开炮能清除一行或者一列的asteroid

  求最少的开炮次数

  建模:若存在点(u,v),则建一条从u到v的有向路

        容易看出,这是一个二分图,每一条边表示表格中的一个点

        问题转换为:求最少的点,使得每条边都能被这些点匹配到

        也就是一个最小点覆盖的问题,那么有一个结论是:最小点覆盖=最大匹配

        我们只需要求最大的匹配数即可 

*/ 

#include<iostream>

#include<cstdio>

#include<cstdlib>

#include<vector>

#include<set>

#include<queue>

#include<map>

#include<cmath>

#include<cstring>

#include<algorithm>

#include<functional>

using namespace std;

const int INF=(1<<31)-1;

const double EPS=1e-8;

const int N=510;

int n,m,k;// X集合有n个点,Y集合有m个点,二分图中有k条边 

bool path[N][N];// p[i][j]表示X集合中的点i到Y集合中的点j是否有路

int mate_x[N];// mate_x[i]表示X集合中的i在Y中匹配的点,初始为-1 ,每次都从X集合开始进行增广路的查找 

int mate_y[N];// mate_y[i]表示Y集合中的i在X中匹配的点 ,初始为-1 

int visited[N];// 每次从集合X中的点开始增广路的查找,所以用visited来记录“本次增广路查找”,Y集合中的i是否被匹配 

 

int find(int u)

{

  for(int v=1;v<=m;v++)//查找Y集合中的点 

    if(!visited[v]&&path[u][v])//Y中的v还未进行搜索,并且u到v有路 

    {

       visited[v]=true; // 无论能否找到增广路,标记v在本次查找中已经被访问了                           

       if(mate_y[v]==-1||find(mate_y[v]))

       /*

         1。 v还未被匹配(递归出口)

         2。 v已经被匹配,并且能从v所匹配的点,查找到一条增广路

         3。 重新标记v的匹配为u,u的匹配为v(即把增广路取反) 

       */ 

       {

          mate_y[v]=u;

          mate_x[u]=v;

          return 1;                                  

       }                        

    }    

  return 0;  

 

int main()

{

    while(cin>>n>>k)

    {

       m=n;

       int u,v;

       memset(path,false,sizeof(path));

       while(k--)

       {

         scanf("%d %d",&u,&v);

         path[u][v]=true;          

       }               

       int ans=0;

       memset(mate_x,-1,sizeof(mate_x));

       memset(mate_y,-1,sizeof(mate_y));

       for(u=1;u<=n;u++)

       {

         memset(visited,false,sizeof(visited));

         if(mate_x[u]==-1&&find(u))ans++;                 

       }

       printf("%d/n",ans);

    }

    return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值