poj 3041

来源:互联网 发布:恐怖故事2剧情解析知乎 编辑:程序博客网 时间:2024/06/17 07:50


//相关知识点

¥     最小覆盖: 最小覆盖要求用最少的点(X集合或Y集合的都行)让每条边都至少和其中一个点关联。可以证明:最少的点(即覆盖数)=最大匹配数 M

¥     简单的证明如下:

¥     (1)M个是足够的。只需要让它们覆盖最大匹配的M条边,则其它边一定被覆盖(如果有边e不被覆盖,把e加入后得到一个更大的匹配)

¥     (2)M个是必需的,仅考虑形成最大匹配的这M条边,由于它们两两之间没有公共点,因此至少需要M个点才可以把它们覆盖

 

 

 

对于这题 那个数据我们可以用下面的表示,0表示无障碍物,1表示有;

1 0 1

0 1 0

0 1 0

首先,我们利用行跟列做二分图:

 

如果第i行的第j列有障碍物,则在图中左边的i行连一条边到右边的j列,上面的数据

于是问题就转化成最小点覆盖的问题.求最大匹配即可.

 

Code:

#include<iostream>using namespace std; bool map[502][502];int linkx[502],linky[502];//linkx表示x所对应的y,linky表示y所对应的xbool used[502]; int n; int path(int x){       for(inti=1;i<=n;i++)//y轴遍历       {              if(!used[i]&&map[x][i])              {                     used[i]=true;//别忘咯                     if(linky[i]==-1||path(linky[i]))                     {                            linky[i]=x;                            linkx[x]=i;                            return1;                     }              }       }       return0;} int main(){       intk,num,a,b,i;       while(scanf("%d%d",&n,&k)!=EOF)       {              memset(map,false,sizeof(map));              while(k--)              {                     scanf("%d%d",&a,&b);                     map[a][b]=true;              }              num=0;              memset(linkx,0xff,sizeof(linkx));              memset(linky,0xff,sizeof(linky));              for(i=1;i<=n;i++)//x轴              {                     if(linkx[i]==-1)//x轴不存在路径                     {                            memset(used,false,sizeof(used));                            num+=path(i);//                     }              }              printf("%d\n",num);       }       return0;}