4443: [Scoi2015]小凸玩矩陣
阿新 • • 發佈:2018-11-29
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()); }