4443: [Scoi2015]小凸玩矩阵Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 1954 Solved: 937
[Submit][Status][Discuss]
Description
小凸和小方是好朋友,小方给小凸一个N*M(N<=M)的矩阵A,要求小秃从其中选出N个数,其中任意两个数字不能在同一行或同一列,现小凸想知道选出来的N个数中第K大的数字的最小值是多少。
Input
第一行给出三个整数N,M,K
接下来N行,每行M个数字,用来描述这个矩阵
Output
如题
Sample Input
3 4 2
1 5 6 6
8 3 4 3
6 8 6 3
Sample Output
3
HINT
1<=K<=N<=M<=250,1<=矩阵元素<=10^9
...心态崩了
把行和列拆开然后就可以二分图匹配
然后就没了
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<cstring>
#define M 1000000
using namespace std;
int a[M],d[M],i,m,n,j,k,ver[M],edge[M],head[M],nex[M],cnt=1,s,t,p,ans,x,y,cost[M],r,l=0x3f3f3f3f,cur[M];
queue <int>q;
inline void add(int x,int y,int z)
{
ver[++cnt]=y; nex[cnt]=head[x]; head[x]=cnt; edge[cnt]=1; cost[cnt]=z;
ver[++cnt]=x; nex[cnt]=head[y]; head[y]=cnt; edge[cnt]=0; cost[cnt]=z;
}
bool bfs(int z)
{
memset(d,0,sizeof(d));
for(i=0;i<=t;i++) cur[i]=head[i];
while(q.size()) q.pop();
q.push(0); d[0]=1;
while(q.size())
{
int x=q.front(); q.pop();
for(int i=head[x];i;i=nex[i])
if(edge[i] && !d[ver[i]] && cost[i]<=z)
{
q.push(ver[i]);
d[ver[i]]=d[x]+1;
if(ver[i]==t) return 1;
}
}
return 0;
}
int dinic(int x,int flow,int z)
{
int re=flow;
if(x==t) return flow;
if(!flow) return 0;
for(int i=cur[x];i;i=nex[i])
if(edge[i]==1 && d[ver[i]]==d[x]+1 && cost[i]<=z)
{
cur[x]=i;
int s=dinic(ver[i],min(re, edge[i]),z);
if(!s) d[ver[i]]=0;
edge[i]-=s; edge[i^1]+=s;
re-=s;
if(!re) break;
}
return flow-re;
}
bool check(int x)
{
int ans=0;
while(bfs(x))
while(s=dinic(0,0x3f3f3f3f,x)) ans+=s;
for(int i=1;i<=cnt;i++) if(!(i&1)) edge[i]=1; else edge[i]=0;
if(ans>=n-k+1) return 1;
return 0;
}
int erfen()
{
int tmp=r;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(mid)) tmp=mid, r=mid-1;
else l=mid+1;
}
return tmp;
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
t=n+m+1;
for(i=1;i<=n;i++) add(0,i,0);
for(i=1;i<=m;i++) add(n+i,t,0);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
{
scanf("%d",&s);
add(i,n+j,s);
r=max(r,s);
l=min(l,s);
}
printf("%d",erfen());
}