Problem B.Bullet
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 73 Accepted Submission(s): 36
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×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 Aij represents the experience of the monster at grid (i,j). If Aij=0, there is no monster at grid (i,j).(Aij≤1e9)
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
题目大意:每行每列最多取一个数,构成的集合在满足元素数量最多的前提下,最小值最大。 最小值增大时,可匹配边的数量减少,所以最大匹配可能减小,于是可以二分最小值,每次求图中权值大于最小值的边的最大匹配。
解题思路:二分图最大匹配 + Hungarian 算法。
AC 代码
/
#include<bits/stdc++.h> #include<cmath> #define mem(a,b) memset(a,b,sizeof a); #define INF 0x3f3f3f3f using namespace std; typedef long long ll; const int maxn=510; struct edge { int to,nx,w; }eds[maxn*maxn]; int n, cnt; int linker[maxn], vis[maxn], head[maxn]; void init() { cnt=0; mem(head,-1); } void addEdge(int u, int v, int w) { eds[cnt].to=v; eds[cnt].w=w; eds[cnt].nx=head[u]; head[u]=cnt++; } bool dfs(int u,int limit) { int v; for(int i=head[u];i!=-1;i=eds[i].nx) { v=eds[i].to; if(eds[i].w>=limit && !vis[v]) { vis[v]=1; if(!linker[v]||dfs(linker[v],limit)) { linker[v]=u; return 1; } } } return 0; } int jde(int limit) { mem(linker,0); cnt=0; for(int i=0;i<n;i++) { mem(vis,0); if(dfs(i,limit)) cnt++; } return cnt; } int main() { while(~scanf("%d",&n)) { init(); int w; for(int i=0;i<n;i++) for(int j=0;j<n;j++) { scanf("%d",&w); addEdge(i,j,w); } int ans=jde(1); // 求出最大匹配数 int l=0,r=INT_MAX; while(r>=1) // 二分思想,可自己模拟下就明白了 { if(jde(l+r)==ans) l+=r; else r>>=1; } printf("%d\n",max(1,l)); } return 0; }