bzoj4443[SCOI2015]小凸玩矩阵
题意:一个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]小凸玩矩阵的更多相关文章
- 2018.06.30 BZOJ4443: [Scoi2015]小凸玩矩阵(二分加二分图匹配)
4443: [Scoi2015]小凸玩矩阵 Time Limit: 10 Sec Memory Limit: 128 MB Description 小凸和小方是好朋友,小方给小凸一个N*M(N< ...
- bzoj4443 SCOI2015 小凸玩矩阵 matrix
传送门:bzoj4443 题解 很水的一道网络流,显然可以二分答案,然后我们希望第\(k\)大尽量小,那么对于一个\(mid\),我们应尽量选择更小的,然后跑二分图最大匹配来验证. code
- 【BZOJ4443】[Scoi2015]小凸玩矩阵 二分+二分图最大匹配
[BZOJ4443][Scoi2015]小凸玩矩阵 Description 小凸和小方是好朋友,小方给小凸一个N*M(N<=M)的矩阵A,要求小秃从其中选出N个数,其中任意两个数字不能在同一行或 ...
- BZOJ_4443_[Scoi2015]小凸玩矩阵_二分+二分图匹配
BZOJ_4443_[Scoi2015]小凸玩矩阵_二分+二分图匹配 Description 小凸和小方是好朋友,小方给小凸一个N*M(N<=M)的矩阵A,要求小秃从其中选出N个数,其中任意两个 ...
- 【BZOJ4443】小凸玩矩阵(二分答案,二分图匹配)
[BZOJ4443]小凸玩矩阵(二分答案,二分图匹配) 题面 BZOJ Description 小凸和小方是好朋友,小方给小凸一个N*M(N<=M)的矩阵A,要求小秃从其中选出N个数,其中任意两 ...
- BZOJ 4443: [Scoi2015]小凸玩矩阵 最大流
4443: [Scoi2015]小凸玩矩阵 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=4443 Description 小凸和小方是好 ...
- bzoj 4443 [Scoi2015]小凸玩矩阵 网络流,二分
[Scoi2015]小凸玩矩阵 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1564 Solved: 734[Submit][Status][Di ...
- 【bzoj4443】【[Scoi2015]小凸玩矩阵】二分+二分图最大匹配
(上不了p站我要死了,侵权度娘背锅) Description 小凸和小方是好朋友,小方给小凸一个N*M(N<=M)的矩阵A,要求小秃从其中选出N个数,其中任意两个数字不能在同一行或同一列,现小凸 ...
- [bzoj4443] [loj#2006] [洛谷P4251] [Scoi2015]小凸玩矩阵
Description 小凸和小方是好朋友,小方给小凸一个 \(N \times M\)( \(N \leq M\) )的矩阵 \(A\) ,要求小秃从其中选出 \(N\) 个数,其中任意两个数字不能 ...
随机推荐
- CSS3 border-radius 圆角属性
使用 CSS3 border-radius 属性,你可以给任何元素制作 "圆角". 浏览器支持 表格中的数字表示支持该属性的第一个浏览器的版本号. -webkit- 或 -moz- ...
- javascript 表单
在HTML中,表单是由<form>元素来组成的.在js中,表单对应的则是HTMLFormElement类型.它和其他HTML元素一样具有相同的默认属性.下面是HTMLFormElement ...
- [deviceone开发]-do_Album的简单示例
一.简介do_Album用来打开手机系统提供的相册,能选择一张或多张图片返回给开发者,通常相册的图片比较大,要经过缩放.有的时候用户也需要把别的地方获取到到图片收藏到系统相册.这个示例简单展示这个组件 ...
- Atitit.http httpclient实践java c# .net php attilax总结
Atitit.http httpclient实践java c# .net php attilax总结 1. Navtree>> net .http1 2. Httpclient理论1 2. ...
- Android 开源库和项目 2
1.带尾巴的RecyclerViewPager 特点:1.像viewPager一样滑动一次就滑动一页 2.像画廊gallery一样,滑动一次可以滑动很多页 3.竖向滑动 4.支持点击事件,没有错乱 ...
- word 2010 建立多级结构和目录
点击“开始”中的“样式”中右下角按钮 点击弹出窗口中最下方第三个按钮 点击“推荐”选项卡,再选择要显示的标题,然后点击“显示”.然后按照需要,分别把“标题3”“标题4”等显示.最后点确定即可. ...
- Web系统性能测试术语简介
并发用户 并发一般分为两种情况.一种是严格意义上的并发,即所有的用户在同一时刻做同一件事情或者操作.这种操作一般指做同一类型的业务,比如在信用卡审批业务中,一定数目的用户在同一时刻对已经完成的审批业务 ...
- war 文件打包技巧
1.首先是工具比如Eclipse很方便了. 2.用winrar之类的工具,把web-info目录,及跟它同级的所有目录及文件,打包成 zip文件就行了,然后把扩展名改成war! 3 Jar命令: 假定 ...
- Linux查看物理CPU个数、核数、逻辑CPU个数
# 总核数 = 物理CPU个数 X 每颗物理CPU的核数 # 总逻辑CPU数 = 物理CPU个数 X 每颗物理CPU的核数 X 超线程数 # 查看物理CPU个数 cat /proc/cpuinfo| ...
- 使用selenium编写脚本常见问题(一)
前提:我用selenium IDE录制脚本,我用java写的脚本,如果大家想看的清楚明白推荐java/Junit4/Webdriver 我用的是java/TestNG/remote control 1 ...