BZOJ4443: [Scoi2015]小凸玩矩阵
Posted tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ4443: [Scoi2015]小凸玩矩阵相关的知识,希望对你有一定的参考价值。
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
1 5 6 6
8 3 4 3
6 8 6 3
Sample Output
3
HINT
1<=K<=N<=M<=250,1<=矩阵元素<=10^9
二分答案x,然后“存在方案使得第K大的数<=x”等价于“存在方案选n-k+1个数<=x”。
那么二分图匹配即可。
#include<cstdio> #include<cctype> #include<queue> #include<cmath> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i;i=next[i]) using namespace std; const int BufferSize=1<<16; char buffer[BufferSize],*head,*tail; inline char Getchar() { if(head==tail) { int l=fread(buffer,1,BufferSize,stdin); tail=(head=buffer)+l; } return *head++; } inline int read() { int x=0,f=1;char c=Getchar(); for(;!isdigit(c);c=Getchar()) if(c==‘-‘) f=-1; for(;isdigit(c);c=Getchar()) x=x*10+c-‘0‘; return x*f; } const int maxn=510; const int maxm=200010; const int inf=1e9; struct ISAP{ struct tedge{int x,y,w,next;}adj[maxm];int ms,fch[maxn]; int d[maxn],s[maxn],cur[maxn],gap[maxn],n,top; void init(int n){ this->n=n;ms=0;top=0; memset(d,-1,sizeof(d)); memset(fch,-1,sizeof(fch)); return; } void AddEdge(int u,int v,int w){ adj[ms]=(tedge){u,v,w,fch[u]};fch[u]=ms++; adj[ms]=(tedge){v,u,0,fch[v]};fch[v]=ms++; return; } void bfs(){ queue<int>Q;Q.push(n);d[n]=0; while(!Q.empty()){ int u=Q.front();Q.pop(); for(int i=fch[u];i!=-1;i=adj[i].next){ int v=adj[i].y; if(d[v]==-1) d[v]=d[u]+1,Q.push(v); } } return; } int solve(int S,int T){ n=T;bfs();int k=S,i,flow=0; for(i=0;i<=n;i++) cur[i]=fch[i],gap[d[i]]++; while(d[S]<n){ if(k==n){ int mi=inf,pos; for(i=0;i<top;i++) if(adj[s[i]].w<mi) mi=adj[s[i]].w,pos=i; for(i=0;i<top;i++) adj[s[i]].w-=mi,adj[s[i]^1].w+=mi; flow+=mi;top=pos;k=adj[s[top]].x; } for(i=cur[k];i!=-1;i=adj[i].next){ int v=adj[i].y; if(adj[i].w&&d[k]==d[v]+1){cur[k]=i;k=v;s[top++]=i;break;} } if(i==-1){ int lim=n; for(i=fch[k];i!=-1;i=adj[i].next){ int v=adj[i].y; if(adj[i].w&&d[v]<lim) lim=d[v],cur[k]=i; } if(--gap[d[k]]==0) break; d[k]=lim+1;gap[d[k]]++; if(k!=S) k=adj[s[--top]].x; } } return flow; } }sol; int n,m,k,val[maxn][maxn]; int check(int x) { int S=n+m+1,T=n+m+2;sol.init(T); rep(i,1,n) sol.AddEdge(S,i,1); rep(i,1,m) sol.AddEdge(i+n,T,1); rep(i,1,n) rep(j,1,m) if(val[i][j]<=x) sol.AddEdge(i,j+n,1); return sol.solve(S,T)>=n-k+1; } int main() { n=read();m=read();k=read(); int l=inf,r=-inf,mid; rep(i,1,n) rep(j,1,m) { val[i][j]=read(); l=min(l,val[i][j]); r=max(r,val[i][j]); } while(l<r) if(check(mid=l+r>>1)) r=mid; else l=mid+1; printf("%d\n",l); return 0; }
以上是关于BZOJ4443: [Scoi2015]小凸玩矩阵的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ4443[Scoi2015]小凸玩矩阵 二分+二分图最大匹配
bzoj4443[Scoi2015]小凸玩矩阵 二分+二分图匹配