Bullet二分图 匈牙利+二分

A . Bullet
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×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 n(n≤500)
Then n lines follow. In each line there are n integers, and Aijrepresents the experience of the monster at grid(i,j). If Aij=0, there is no monster at grid(i,j).
Aij≤109
Output
One integer, the value of max experience.

Samples
Input 复制
2
2 0
1 8
Output
2

题意:
大概为n*n的矩阵 0代表没有怪兽

打怪兽需要注意 如果打了当前这个怪兽 那么这个怪兽所在的行和列其他怪兽都不能打了
所以 如果以行为基准的话 行和列进行二分图匹配 就可以得到最多可以打几个怪兽
但是他又让求在你打的这些怪兽中 最小经验值最大 意思就是 让最小值尽可能的大点
类似 极限 就是说如果 目前这个最小经验值已经最大了 如果再大的话 那么就不能打最多的怪兽了
所以这里利用二分最小经验值 小于最小经验值的置0 代表没有怪兽
然后重新进行 行和列的二分图匹配 得到新的打怪兽数量 如果数量和初始值一样 就说明当前最小经验值可以满足 那么l=mid 求再大点的最小经验值 否则 r=mid-1 使最小经验值再小点

然后代码

#include <map>
#include <stack>
#include <queue>
#include <vector>
#include <math.h>
#include <string>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <time.h>
#include <set>
#include <list>
#include <iostream>

using namespace std;
//map<string,string>ip;
//map<string,bool>cy; 

typedef long long ll;
const int maxn=500+188;
const ll inf=1e11;
ll n,m,k,flag,cnt,sum;
/*
struct node{
	int x,y,w;
	operator <(node a){
		return w<a.w;
	}
};*/
int a[maxn][maxn];int G[maxn][maxn];
int from[maxn];
bool vis[maxn];// 二分图
bool match(int x){
	for(int i=1;i<=n;i++){
		if(!vis[i]&&a[x][i]){
			vis[i]=1;
			if(from[i]==-1||match(from[i])){
				from[i]=x;
				return 1;
			}
		}
	}
	return 0;
} 

int solve(){
	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){
	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];
			else a[i][j]=0;
		}
	}
	int ans=solve();
	if(ans<sum) return 0;
	return 1;
}
int main(){
	cin>>n;int l=1000000000,r=-1;
	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,a[i][j]); r=max(r,a[i][j]);
		}
	}
	sum=solve();
	while(l<r){
		int mid=(l+r+1)>>1;
		if(!check(mid)) r=mid-1;
		else l=mid;
	}
	cout<<l;
	return 0;
} 
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

牛郎恋刘娘,刘娘念牛郎

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值