2018第九届山东省ACM——B Bullet

题目来源:https://acm.sdut.edu.cn/onlinejudge2/index.php/Home/Index/problemdetail/pid/4215.html

Bullet

Time Limit: 1000 ms Memory Limit: 65536 KiB

Submit Statistic Discuss

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;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值