题目来源:https://acm.sdut.edu.cn/onlinejudge2/index.php/Home/Index/problemdetail/pid/4215.html
Bullet
Time Limit: 1000 ms Memory Limit: 65536 KiB
Problem Description
In GGO, a world dominated by gun and steel, players are fighting for the honor of being the strongest gunmen. Player Shino is a sniper, and her aimed shot kills one monster at a time. Now she is in an n \times nn×n map, and there are monsters in some grids. Each monster has an experience. As a master, however, Shino has a strange self-restrain. She would kill at most one monster in a column, and also at most one in a row. Now she wants to know how to get max experience, under the premise of killing as many monsters as possible.
Input
The first line contains an integer nn. (n<=500)
Then n lines follow. In each line there are n integers, and AijAij represents the experience of the monster at grid (i,j)(i,j). If Aij=0Aij=0, there is no monster at grid (i,j)(i,j).
The experience is the minimal experience of all the monster which are killed.
It guaranteed that the maximum of the experience of the monster is not larger than 10^9
Output
One integer, the value of max experience.
Sample Input
2
2 0
1 8
Sample Output
2
Hint
Source
“浪潮杯”山东省第九届ACM大学生程序设计竞赛(感谢山东财经大学)
题意:
给定一个n*n的地图,每个位置处可能会有monster,对每个monster,杀掉它后会获得一定的经验值。每行、每列可以而且仅可以杀一只。让杀掉后获得的所有经验值中,最小值最大。
思路:
二分答案+二分图匹配。
首先对最小的经验值进行二分,地图中的所有经验值<mid 的点直接删除(经验值为0,即不杀此位置的monster),对处理后的图进行二分图最大匹配,看看匹配所得的最大值是否与原图的最大匹配结果相同,由此进行二分的值的检验。
求取二分图的最大匹配可用匈牙利算法。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 510;
int n;
int g[maxn][maxn];
int a[maxn][maxn];
int cnt = 0;
int from[maxn];
bool vis[maxn];
bool match(int x) {
for (int i = 1; i <= n; ++i) {
if (a[x][i] && vis[i] == 0) {
vis[i] = 1;
if (from[i] == -1 || match(from[i])) {
from[i] = x;
return 1;
}
}
}
return 0;
}
int hungry() {
int tot = 0;
memset(from, -1, sizeof(from));
for (int i = 1; i <= n; ++i) {
memset(vis, 0, sizeof(vis));
if (match(i))
++tot;
}
return tot;
}
bool check(int x) {
memset(a, 0, sizeof(a));
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
if (g[i][j] >= x)
a[i][j] = g[i][j];
}
}
int tot = hungry();
if (tot < cnt)return 0;
else return 1;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
while (cin >> n) {
memset(g, 0, sizeof(g));
int l = 1e9, r = 0;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
cin >> g[i][j];
a[i][j] = g[i][j];
l = min(l, g[i][j]);
r = max(r, g[i][j]);
}
}
cnt = hungry();
while (l < r) {
int mid = (l + r + 1) / 2;
if (check(mid))l = mid;
else r = mid - 1;
}
cout << l << endl;
}
return 0;
}