题意:
给定一个n*n矩阵,矩阵内值非零表示该处有怪物且怪物的经验值为矩阵内值。每一行每一列至多消灭一个怪物,现要求消灭最大的怪物,并在这个前提下求出能获得的最大经验值。你所获得的经验值为你所消灭的所有怪物的经验值中最小的那个。
分析:
二分图最大匹配+二分。
对于所有矩阵内值非零a[i][j],从X部的i点向Y部的j点连一条边。对此二分图求出最大匹配ans。那么ans为最多能消灭的怪物数量。然后二分枚举经验值k,对于所有矩阵内值a[i][j]>=k的,按照上面一样重新建图并求出最大匹配sum。如果sum等于ans,那么经验值k是合法的。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 509;
const int MAXM = 250009;
int tu[MAXN][MAXN];
struct edge{
int to,next;
}edge[MAXM];
int head[MAXM],tot;
void init()
{
tot = 0;
memset(head,-1,sizeof head);
}
int ANS;
void addedge(int u,int v)
{
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
}
int linker[MAXN];
bool used[MAXN];
int uN,n;
bool dfs(int u)
{
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v = edge[i].to;
if(!used[v])
{
used[v] = true;
if(linker[v]==-1||dfs(linker[v]))
{
linker[v] = u;
return 1;
}
}
}
return false;
}
int hungry()
{
int res =0 ;
memset(linker,-1,sizeof linker);
for(int u=1;u<=uN;u++)
{
memset(used,0,sizeof used);
if(dfs(u))res++;
}
return res;
}
bool check(int k)
{
init();
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(tu[i][j]>=k)
{
addedge(i,j);
}
}
}
return hungry()==ANS;
}
int main()
{
cin>>n;
uN = n;
init();
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%d",&tu[i][j]);
if(tu[i][j]>0)
addedge(i,j);
}
}
ANS = hungry();
int l =0 ,r = 1e9;
while(l<r)
{
int mid = (l+r+1)>>1;
if(check(mid))
{
l = mid;
}
else r = mid-1;
}
printf("%d\n",l);
}
#include<cstdio>
#include<algorithm>
using namespace std;
struct s{
int va, x, y;
};
s arr[505*505];
bool cmp(s a,s b){
if(a.va!=b.va)return a.va < b.va;
if(a.x!=b.x)return a.x < b.x;
return a.y < b.y;
}
int main(){
int N, len;
int dir_c[505] = {0}, dir_r[505] = {0};
scanf("%d",&N);
len = N * N;
for(int i=1;i<=N;i++){
dir_c[i] = dir_r[i] = N;
for(int j=1;j<=N;j++){
scanf("%d",&arr[(i-1)*N+j].va);
arr[(i-1)*N+j].x = i;
arr[(i-1)*N+j].y = j;
//dir_c[i]++,dir_r[j]++;
}
}
sort(arr+1,arr+1+len,cmp);
for(int i=1;i<=len;i++){
if(arr[i].va && (dir_c[arr[i].x]<=1||dir_r[arr[i].y]<=1)){
printf("%d\n",arr[i].va);
break;
}
dir_c[arr[i].x]--,dir_r[arr[i].y]--;
}
return 0;
}
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
struct data {
int ai, x, y;
}a[510 * 510];
bool cmp(data x, data y) {
if(x.ai != y.ai) return x.ai < y.ai;
else if(x.x != y.x) return x.x < y.x;
return x.y < y.y;
}
int d_c[510], d_r[510];
int main() {
int n, i, j, len;
scanf("%d", &n);
len = n * n;
for(i = 1; i <= n; ++ i)
for(j = 1; j <= n; ++ j) {
scanf("%d", &a[(i - 1) * n + j].ai);
a[(i - 1) * n + j].x = i;
a[(i - 1) * n + j].y = j;
d_c[i] ++, d_r[j] ++;
}
sort(a + 1, a + 1 + len, cmp);
for(i = 1; i <= len; ++ i) {
if(a[i].ai != 0 && (d_c[a[i].x] <= 1 || d_r[a[i].y] <= 1)) {
printf("%d\n", a[i].ai);
break ;
}
d_c[a[i].x] --, d_r[a[i].y] --;
}
return 0;
}
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=505,M=(N*N+2*N)*2,inf=2e9;
int n,S,T,tt,tot,h[N*2],to[M],nx[M],c[M],l[N*2],q[N*2];
struct edg{
int v,a,b;
void in(int _a,int _b,int _c){
a=_a,b=_b,v=_c;
}
bool operator<(const edg &r)const{
return v<r.v;
}
}e[N*N];
void add(int u,int v){
to[++tt]=v,nx[tt]=h[u],h[u]=tt,c[tt]=1;
to[++tt]=u,nx[tt]=h[v],h[v]=tt,c[tt]=0;
}
inline bool bfs(){
memset(l,0,T+1<<2);
int f,r;
l[q[f=r=1]=S]=1;
while(f<=r){
int x=q[f++];
for(int i=h[x];i;i=nx[i])
if(c[i]>0&&!l[to[i]])
l[q[++r]=to[i]]=l[x]+1;
}return l[T]>0;
}
inline int dfs(int p,int C) {
if(p==T||!C) return C;
int r=C,t;
for(int i=h[p];i;i=nx[i])
if(c[i]&&l[to[i]]==l[p]+1){
t=dfs(to[i],min(c[i],r));
r-=t,c[i]-=t,c[i^1]+=t;
if(!r) break;
}
if(r==C) l[p]=0;
return C-r;
}
int flow(int u){
tt=1;for(int i=S;i<=T;++i) h[i]=0;
for(int i=tot;i&&e[i].v>=u;--i)
add(e[i].a,e[i].b+n);
for(int i=1;i<=n;++i)
add(S,i),add(i+n,T);
int ret=0;
while(bfs()) ret+=dfs(S,inf);
return ret;
}
int main(){
scanf("%d",&n);T=2*n+1;
for(int i=1;i<=n;++i)
for(int j=1,a;j<=n;++j){
scanf("%d",&a);
if(a) e[++tot].in(i,j,a);
}
sort(e+1,e+tot+1);
int uu=flow(0),l=1,r=e[tot].v;
while(l<r){
int mid=l+r+1>>1;
if(flow(mid)<uu) r=mid-1;
else l=mid;
}
printf("%d",l);
return 0;
}
vector版(参考):
#include <bits/stdc++.h>
using namespace std;
const int maxn=550;
int n;
int from[maxn],w[maxn][maxn],ans,vis[maxn];
vector<int> g[maxn];
void init()
{
for(int i=0;i<n;i++) g[i].clear();
}
bool Find(int u)
{
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(!vis[v])
{
vis[v]=1;
if(from[v]==-1 || Find(from[v]))
{
from[v]=u;
return true;
}
}
}
return false;
}
int match()
{
int ret=0;
memset(from,-1,sizeof(from));
for(int i=0;i<n;i++)
{
memset(vis,0,sizeof(vis));
if(Find(i)) ret++;
}
return ret;
}
bool check(int k)
{
init();
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(w[i][j]>=k)
g[i].push_back(j);
return match()==ans;
}
int main()
{
while(~scanf("%d",&n))
{
init();
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
scanf("%d",&w[i][j]);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
if(w[i][j])
{
g[i].push_back(j);
}
}
ans=match();
int L=0,R=1e9;
while(L<R)
{
int mid=(L+R+1)>>1;
if(check(mid))
L=mid;
else
R=mid-1;
}
printf("%d\n",L);
}
return 0;
}