1281 (二部圖匹配問題)
阿新 • • 發佈:2018-12-23
小希和Gardon在玩一個遊戲:對一個N*M的棋盤,在格子裡放盡量多的一些國際象棋裡面的“車”,並且使得他們不能互相攻擊,這當然很簡單,但是Gardon限制了只有某些格子才可以放,小希還是很輕鬆的解決了這個問題(見下圖)注意不能放車的地方不影響車的互相攻擊。
所以現在Gardon想讓小希來解決一個更難的問題,在保證儘量多的“車”的前提下,棋盤裡有些格子是可以避開的,也就是說,不在這些格子上放車,也可以保證儘量多的“車”被放下。但是某些格子若不放子,就無法保證放盡量多的“車”,這樣的格子被稱做重要點。Gardon想讓小希算出有多少個這樣的重要點,你能解決這個問題麼?
Input
輸入包含多組資料,
第一行有三個數N、M、K(1<N,M<=100 1<K<=N*M),表示了棋盤的高、寬,以及可以放“車”的格子數目。接下來的K行描述了所有格子的資訊:每行兩個數X和Y,表示了這個格子在棋盤中的位置。
Output
對輸入的每組資料,按照如下格式輸出:
Board T have C important blanks for L chessmen.
Sample Input
3 3 4 1 2 1 3 2 1 2 2 3 3 4 1 2 1 3 2 1 3 2
Sample Output
Board 1 have 0 important blanks for 2 chessmen. Board 2 have 3 important blanks for 3 chessmen.
題意 :必要點:若這個點不放棋子時,就不會達到放的最多的棋子數;找出有多少個這樣的點;
思路:剛看到這個題時,不知道怎做;原來是二部圖匹配,把 座標(x,y) x ,y 各看為二部圖的一方,先找出最大匹配,再判斷去掉一些點,是不是還是最大匹配,若不是,就是必要點, 若 還是最大匹配的話,就不是必要點;
程式碼:
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #include<vector> #define Max 110 vector<int> v[Max]; int mpp[Max][Max],book[Max],match[Max]; int n,m,k; void init() { memset(match,-1,sizeof(match)); memset(mpp,0,sizeof(mpp)); for(int i = 0;i<=n;i++) v[i].clear(); } int dfs(int u) // 匈牙利演算法; { for(int i = 0;i<v[u].size();i++) { int k = v[u][i]; // book[i] 看看這個深搜,右邊的位置上i點是否搜過; if(!book[k]&&mpp[u][k]) // mpp[][]陣列的作用就是在 去掉這個點時,判斷最大匹配數的時的個數是否和不去時相等; { book[k] = 1; // 單向邊,標記的是v不是u; int t = match[k]; if(t < 0||dfs(t)) { match[k] = u; // 最大匹配分為兩部分,當左邊的找右邊的時,單向邊 return 1; // 只讓右邊數存左邊的匹配的位置;自己想想; } } } return 0; } int find() // 找二部圖最大匹配; { int i,j; int res = 0; for(i = 1;i<=n;i++) // 左邊的點; { memset(book,0,sizeof(book)); if(dfs(i)) // 去找右邊的點匹配; res++; } return res; } int main() { int i,j; int num = 1; while(~scanf("%d%d%d",&n,&m,&k)) { int x,y; init(); for(i = 0;i<k;i++) { scanf("%d%d",&x,&y); mpp[x][y] = 1; // 單向邊; v[x].push_back(y); // 存邊; } int mx_p = find(); // 找出最大匹配數 int res = 0; for(i = 1;i<=n;i++) { for(j = 1;j<=m;j++) { if(mpp[i][j]) { memset(match,-1,sizeof(match)); // 每找一次最大匹配要把匹配陣列初始化; mpp[i][j] = 0; // 先去掉這個點,判斷與最大匹配是否相同; int tt=find(); if(tt!= mx_p) // 若不一樣就說明這個點一定能要放棋子; res++; mpp[i][j] = 1; } } } printf("Board %d have %d important blanks for %d chessmen.\n",num++,res,mx_p); } return 0; }