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 Copy
2
2 0
1 8
Output
2
题目大意
给你一个n*n的矩阵,在矩阵中选一个数,选择后该点所在的行和列都不能在选择,然后问你选出的一堆数中的最小值最大是多少
解题思路:
首先,最小值最大化我们可以采用二分答案;
然后 ,如何check 答案?
因为每行每列中只能选一个数字,用二分图行列模型求出最大匹配时多少,记为top
因为我们二分的是 取数方案中的数的最小值,所以我们在建图的时候如果点的权值大于mid我们建一条边,然后跑一个二分图最大匹配,看看在最小值为mid的时候最大匹配与top相等不相等, 继续二分答案;
Code
#include<iostream>
#include<algorithm>
#include<math.h>
#include<queue>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
typedef unsigned long long ull;
const int inf = 0x3f3f3f3f;
const int maxn = 5e5+ 7;
const ll mod = 1000000007;
#define mst(x, a) memset( x,a,sizeof(x) )
#define rep(i, a, b) for(int i=(a);i<=(b);++i)
#define dep(i, a, b) for(int i=(a);i>=(b);--i)
ll read() {
ll x=0;
char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return x;
}
void out(ll x) {
int stackk[40];
if (x < 0) {
putchar('-');
x = -x;
}
if (!x) {
putchar('0');
return;
}
int top = 0;
while (x) stackk[++top] = x % 10, x /= 10;
while (top) putchar(stackk[top--] + '0');
}
ll n,a[666][666],link[666][666],use[666],g[666],top,tmp;
int find(ll x) {
for(int i=1 ; i<=n ; i++) {
if(link[x][i]&&use[i]==0) {
use[i]=1;
if(g[i]==0||find(g[i])) {
g[i]=x;
return 1;
}
}
}
return 0;
}
int check(ll mid) {
ll temp=0;
mst(g,0);
for(int i=1 ; i<=n ; i++) {
mst(use,0);
if(find(i)) temp++;
}
if(temp==top) return 1;
return 0;
}
int main() {
n=read();
ll tt=0;
for(int i=1 ; i<=n ; i++) {
for(int j=1 ; j<=n ; j++) {
a[i][j]=read();
if(a[i][j]) link[i][j]=1;
tt=max(tt,a[i][j]);
}
}
if(tt==0) {
puts("0");
return 0;
}
for(int i=1 ; i<=n ; i++) {
mst(use,0);
if(find(i)) top++;
}
ll l=1,r=tt,ans;
while(l<=r) {
ll mid=(l+r)>>1;
mst(link,0);
rep(i,1,n) rep(j,1,n) if(a[i][j]>=mid&&mid) link[i][j]=1;
if(check(mid)) {
l=mid+1;
ans=mid;
} else r=mid-1;
}
out(ans);
return 0;
}
/*
*/