1281(二分圖--匈牙利演算法)
阿新 • • 發佈:2018-12-19
HDU - 1281(二分圖–匈牙利演算法)
小希和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.
- 題目大意: 給你一個棋盤,大小是n*m的,其中有k個點能放棋子,並且每一行,每一列只能放一個棋子,假設你這時候最多放x個棋子,如果能放棋子的k個點中的一個點,讓最多放的棋子數<x,那麼這個點就是重要點,讓你求的就是k個點中的重要點的個數。
- 解題思路:
這是一個二分圖匹配的問題,因為每一行每一都只能放一個棋子,所以說,就變成了x和y的匹配問題。所以我們可以先用匈牙利演算法算出最多有多少個x能匹配到y,然後再遍歷那k個點,看把這個點去掉後,能不能讓最大匹配數減少,減少就是重要點,記錄重要點的個數並輸出。
匈牙利演算法的簡單介紹
因為我自己講感覺講不明白所以就引用一下大佬的部落格吧匈牙利演算法趣談
- AC程式碼:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n,m,k;
int mp[110][110];///用來存圖
int used[110];//用來標記用沒用過這個點
int ans[110];//用來記錄匹配
int x[11000];
int y[11000];
bool find(int x)
{
for(int i=1;i<=m;i++)//遍歷每一個y
{
if(mp[x][i]==1&&used[i]==0)///有相連線的邊 並且沒有每用過
{
used[i]=1;
if(ans[i]==0||find(ans[i]))///y[i]沒有匹配 或者 能給原來和 y[i]匹配的再安排一個
{
ans[i]=x;
return true;
}
}
}
return false ;
}
void init()
{
memset(mp,0,sizeof(mp));
memset(ans,0,sizeof(ans));
}
int solve()
{
int sum=0;
memset(ans,0,sizeof(ans));
for(int i=1;i<=n;i++)///遍歷每個X
{
memset(used,0,sizeof(used));
if(find(i))
sum++;
}
return sum;
}
int main()
{
int Case = 1;
while(scanf("%d%d%d", &n, &m, &k) != EOF)
{
init();
for(int i = 1; i <= k; i++)
{
cin>>x[i]>>y[i];
mp[x[i]][y[i]] = 1;
}
int cnt = solve();
int sum = 0;
for(int i = 1; i <= k; i++)
{
mp[x[i]][y[i]] = 0;
int tmp = solve();
mp[x[i]][y[i]] = 1;
if(tmp < cnt) sum++;
}
printf("Board %d have %d important blanks for %d chessmen.\n", Case++, sum, cnt);
}
return 0;
}