poj 3041


//相關知識點

¥     最小覆蓋: 最小覆蓋要求用最少的點(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所對應的x
bool 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;
}


發佈了41 篇原創文章 · 獲贊 5 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章