1. 程式人生 > >二分圖匹配 --- 最大獨立集

二分圖匹配 --- 最大獨立集

結論 : 最大獨立集 = 結點總數 - 最大匹配數(最小點覆蓋數).
//解釋: 最大獨立集, 即選擇儘量多的結點, 使得任意兩個節點不相鄰(即任意一條邊的兩個端點不會同時被選中), 最大獨立集和最小點覆蓋是互補的. 因此可以得出答案. 至於為什麼是互補的, 就請好好想想. (白書P356)
//提示:
覆蓋集 : 對於每條邊, 至少有一個點要被選中.
獨立集 : 對於每條邊, 至少有一個點不被選中.

經典例題:
LA – 3415
//給出四個條件, 問你n個學生中最多可以挑多少個學生, 使得任意兩個學生至少滿足所給的四個條件中的一個.
//這樣我們就可以根據最大獨立集的概念知道這就是最大獨立集的模型. 所以將每一個人作為一個結點, 如果兩個四個條件都不滿足, 那麼他們就不能同時被選擇, 連一條無向邊. 因為每個人不是男生就是女生, 所以這個圖是二分圖. 求出最大獨立集即可. (直接求當然很麻煩, 所以才用的結論啊!!!)

AC Code

/** @Cain*/
const int maxn=500+5;
bool g[maxn][maxn],vis[maxn];
int link[maxn];
int n;
struct node
{
    int h;
    char ginder[5],music[105],sport[105];
}s[maxn];
bool dfs(int x)
{
    for(int i=1;i<=n;i++){
        if(vis[i] || !g[x][i]) continue;
        vis[i] = true;
        if(link[i] == -1
|| dfs(link[i])){ link[i] = x; return true; } } return false; } void solve() { scanf("%d",&n); Fill(g,false); Fill(link,-1); Fill(s,0); for(int i=1;i<=n;i++){ scanf("%d%s%s%s",&s[i].h,s[i].ginder,s[i].music,s[i].sport); } for
(int i=1;i<=n;i++){ for(int j=i+1;j<=n;j++){ if(abs(s[i].h-s[j].h)>40 || !strcmp(s[i].ginder,s[j].ginder)) continue; if(strcmp(s[i].music,s[j].music)!=0 || !strcmp(s[i].sport,s[j].sport)) continue; g[i][j] = g[j][i] =true; //記住要連無向邊!!!(否則為WA),最後的最大匹配數/2.因為連了兩次. //為什麼要連無向邊了,假如有4個學生,12,23,34不能在一起,如果是連單向邊則答案是1,但實際上答案是2 //這個顯而易見,所以要連無向邊才能滿足這個性質. 實際上從題意上看也可以知道不可能答案為1. xx. //好好理解下. } } int res = 0; for(int i=1;i<=n;i++){ Fill(vis,false); if(dfs(i)) res++; } printf("%d\n",n-res/2); }