题意:一个n*m的矩阵(n<=m<=250),要求选出n个数(每行,每列最多选一个),求第k大数的最小值。

首先第k大的意思是从大到小的第k个数(我读错了,WA了一次还以为算法不对...)

然后第k大最小不好直接做.考虑二分答案.

二分答案的单调性在于,如果不能选出n-k+1个小于等于i的不同行列的数,那么最终的答案大于i,否则最终的答案小于等于i。

判定的时候将每一行看作一个点,每一列也看作一个点,每个位置A[i][j](A[i][j]小于等于判定的答案ans)代表一条第i行和第j行之间的边。(这种二维矩阵每一行怎么样怎么样每一列怎么样怎么样的题常常可以转化成二分图去考虑)。

最后二分出一个i,使得我们可以选出n-k+1个小于等于i的数但不能选出n-k+1个小于等于(i-1)的数,这个i就是答案.

这里有一点问题,就是我们虽然可以选出n-k+1个小于等于i的数,但似乎并没有保证可以选出k-1个大于i的数.因此我在读错题WA了一发之后开始怀疑算法正确性。

所幸,随便选出剩下k-1个数一定可以保证第k大的数字是i.

证明如下:

首先,我们选出所有数字之后,不可能选出n-k+1个小于等于(i-1)的数(否则与二分的结果相违背)。也就是说,我们在选出n-k+1个小于等于i的数之后,随便选剩下的k-1个数字,最终选出的全部数字中至少有k个大于等于i.

于是我们有两个条件:全部数字中,至少有n-k+1个小于等于i(二分条件保证可以先选出n-k+1个这样的数,这个条件等价于从小到大第n-k+1个数也就是从大到小第k个数一定小于等于i),至少有k个大于等于i(也就是说从大到小第k个数一定大于等于i),那么第k大的数既小于等于i又大于等于i,所以第k大的数只能是i,这样就没有问题了。

(似乎别人的题解都觉得这是显然的)

(写了个dinic结果比别人的匈牙利慢好多)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=;
int n,m,k;
int a[maxn][maxn];
struct edge{
int to,next,w;
}lst[maxn*maxn*];int len=,first[maxn*],_first[maxn*];
void addedge(int a,int b,int w){
lst[len].to=b;lst[len].next=first[a];lst[len].w=w;first[a]=len++;
lst[len].to=a;lst[len].next=first[b];lst[len].w=;first[b]=len++;
}
int s,t;
int q[maxn*],vis[maxn*],T,dis[maxn*],head,tail;
bool bfs(){
vis[s]=++T;head=tail=;
q[tail++]=s;dis[s]=;
while(head!=tail){
int x=q[head++];
for(int pt=first[x];pt!=-;pt=lst[pt].next){
if(lst[pt].w&&vis[lst[pt].to]!=T){
vis[lst[pt].to]=T;dis[lst[pt].to]=dis[x]+;
q[tail++]=lst[pt].to;
}
}
}
if(vis[t]==T)memcpy(_first,first,sizeof(first));
return vis[t]==T;
}
int dfs(int x,int lim){
if(x==t)return lim;
int flow=,a;
for(int pt=_first[x];pt!=-;pt=lst[pt].next){
_first[x]=pt;
if(lst[pt].w&&dis[lst[pt].to]==dis[x]+&&(a=dfs(lst[pt].to,min(lst[pt].w,lim-flow)))){
lst[pt].w-=a;lst[pt^].w+=a;flow+=a;
if(flow==lim)break;
}
}
return flow;
}
int dinic(){
int ans=,x;
while(bfs())
while(x=dfs(s,0x7f7f7f7f))ans+=x;
return ans;
}
bool check(int ans){
memset(first,-,sizeof(first));len=;
s=;t=n+m+;
for(int i=;i<=n;++i){
addedge(s,i,);
}
for(int i=;i<=m;++i){
addedge(n+i,t,);
}
for(int i=;i<=n;++i){
for(int j=;j<=m;++j){
if(a[i][j]<=ans)addedge(i,n+j,);
}
}
return dinic()>=k;
}
int main(){
scanf("%d%d%d",&n,&m,&k);
k=n-k+;
for(int i=;i<=n;++i){
for(int j=;j<=m;++j){
scanf("%d",&a[i][j]);
}
}
int l=,r=;
while(l<=r){
int mid=(l+r)>>;
if(check(mid)){
r=mid-;
}else{
l=mid+;
}
}
printf("%d\n",r+);
return ;
}

bzoj4443[SCOI2015]小凸玩矩阵的更多相关文章

  1. 2018.06.30 BZOJ4443: [Scoi2015]小凸玩矩阵(二分加二分图匹配)

    4443: [Scoi2015]小凸玩矩阵 Time Limit: 10 Sec Memory Limit: 128 MB Description 小凸和小方是好朋友,小方给小凸一个N*M(N< ...

  2. bzoj4443 SCOI2015 小凸玩矩阵 matrix

    传送门:bzoj4443 题解 很水的一道网络流,显然可以二分答案,然后我们希望第\(k\)大尽量小,那么对于一个\(mid\),我们应尽量选择更小的,然后跑二分图最大匹配来验证. code

  3. 【BZOJ4443】[Scoi2015]小凸玩矩阵 二分+二分图最大匹配

    [BZOJ4443][Scoi2015]小凸玩矩阵 Description 小凸和小方是好朋友,小方给小凸一个N*M(N<=M)的矩阵A,要求小秃从其中选出N个数,其中任意两个数字不能在同一行或 ...

  4. BZOJ_4443_[Scoi2015]小凸玩矩阵_二分+二分图匹配

    BZOJ_4443_[Scoi2015]小凸玩矩阵_二分+二分图匹配 Description 小凸和小方是好朋友,小方给小凸一个N*M(N<=M)的矩阵A,要求小秃从其中选出N个数,其中任意两个 ...

  5. 【BZOJ4443】小凸玩矩阵(二分答案,二分图匹配)

    [BZOJ4443]小凸玩矩阵(二分答案,二分图匹配) 题面 BZOJ Description 小凸和小方是好朋友,小方给小凸一个N*M(N<=M)的矩阵A,要求小秃从其中选出N个数,其中任意两 ...

  6. BZOJ 4443: [Scoi2015]小凸玩矩阵 最大流

    4443: [Scoi2015]小凸玩矩阵 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=4443 Description 小凸和小方是好 ...

  7. bzoj 4443 [Scoi2015]小凸玩矩阵 网络流,二分

    [Scoi2015]小凸玩矩阵 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1564  Solved: 734[Submit][Status][Di ...

  8. 【bzoj4443】【[Scoi2015]小凸玩矩阵】二分+二分图最大匹配

    (上不了p站我要死了,侵权度娘背锅) Description 小凸和小方是好朋友,小方给小凸一个N*M(N<=M)的矩阵A,要求小秃从其中选出N个数,其中任意两个数字不能在同一行或同一列,现小凸 ...

  9. [bzoj4443] [loj#2006] [洛谷P4251] [Scoi2015]小凸玩矩阵

    Description 小凸和小方是好朋友,小方给小凸一个 \(N \times M\)( \(N \leq M\) )的矩阵 \(A\) ,要求小秃从其中选出 \(N\) 个数,其中任意两个数字不能 ...

随机推荐

  1. 关于docker

    摘要: 最近很多阿里内部的同学和客户私信来咨询如何学习 Docker 技术.为此,我们列了一个路线图供大家学习Docker和阿里云容器服务.这个列表包含了一些社区的优秀资料和我们的原创文章.我们会随着 ...

  2. MarkdownPad 2 常用快捷键

    Ctrl + I : 斜体 Ctrl + B : 粗体 Ctrl + G : 图片 Ctrl + Q : 引用 Ctrl + 1 : 标题 1 Ctrl + 2 : 标题 2 Ctrl + 3 : 标 ...

  3. Android Weekly Notes Issue #226

    Android Weekly Issue #226 October 9th, 2016 Android Weekly Issue #226 本期内容包括: 用Firebase做A/B Test; 用R ...

  4. iOS编码规范

      The official raywenderlich.com Objective-C style guide.   This style guide outlines the coding con ...

  5. Java多线程中的死锁问题

    Java程序基本都要涉及到多线程,而在多线程环境中不可避免的要遇到线程死锁的问题.Java不像数据库那么能够检测到死锁,然后进行处理,Java中的死锁问题,只能通过程序员自己写代码时避免引入死锁的可能 ...

  6. C语言调试过程中duplicate symbol错误分析

    说明:在我们调试C语言的过程中,经常会遇到duplicate symbol错误(在Mac平台下利用Xcode集成开发环境).如下图: 一.简单分析一下C语言程序的开发步骤. 由上图我们可以看出C语言由 ...

  7. 结对项目:代码复审+PSP

    一.代码复审        首先我从代码风格规范和程序修改两方面进行审查. (一)代码风格规范修改 1 . 代码的部分未缩进:在用markdown粘贴代码时,需要后期tab,无形中加大工作量. 2 . ...

  8. Statement对象的executeUpdate返回信息

    int num = sta.executeUpdate(String sql);返回的是我们平时操作数据库客户端时控制台显示的影响行数

  9. PCD文件去除曲率的脚本

    在写一个重建算法的时候需要用到点坐标和法向的数据文件,于是向利用pcl中的法向计算模块来生成法向.输出后法向文件中包含曲率信息,但是这是不需要的.于是自己写了一个python小脚本实现格式转换. #- ...

  10. maven webapp栽坑录

    一.需求 如何将一个java web项目传给别人?放到github上.要想放到github上,就要学会git,markdown和maven.像那些jar包是不鼓励传到github上的,应该尽量把源文件 ...