博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【bzoj4443 scoi2015】小凸玩矩阵
阅读量:5053 次
发布时间:2019-06-12

本文共 2505 字,大约阅读时间需要 8 分钟。

题目描述

小凸和小方是好朋友,小方给了小凸一个 nn × mm (n \leq m)(nm) 的矩阵 AA ,并且要求小凸从矩阵中选出 nn 个数,其中任意两个数都不能在同一行或者同一列。现在小凸想知道,选出的 nn 个数中第 kk 大的数的最小值是多少。

输入输出格式

输入格式:

 11 行读入 33 个整数 n, m, kn,m,k 

接下来 nn 行,每一行有 mm 个数字,第 ii 行第 jj 个数字代表矩阵中第 ii 行第 jj 列的元素 A_{i,j}Ai,j 

输出格式:

输出包含一行,为选出的 nn 个数中第 kk 大数的最小值。

说明

对于 2020 % 的数据, 1 \leq n \leq m \leq 91nm9

对于 4040 % 的数据, 1 \leq n \leq m \leq 22, 1 \leq n \leq 121nm22,1n12

对于 100100 % 的数据, 1 \leq k \leq n \leq m \leq 250, 1 \leq A_{i,j} \leq 10^91knm250,1Ai,j109

 

题意:很清楚;

题解:

①二分第k大的数的最小值,如果a i,j<=mid 行i向列j连边,最后对行列二分图匹配,如果匹配数>=n-k+1向左二分,反之向左;

②说下证明(%%%):有一个事实是对于二分图匹配>=n-k+1成立的答案mid是连续的(具有二分性的),假设最后二分出来的为ans,1~ ans-1显然不行(因为小于等于ans的凑不够n-k+1个),ans+1~max可能不行(因为可能大于等于ans的凑不够k个);所以ans就一定行吗?是的,因为由二分的定义可知,在ans选取的时候,一定会有n-k+1个小于等于ans的值,一定不会有n-k+1个小于ans的值(否则应该是ans-1),则一定会有k+1个大于等于ans的值。

自然ans就是第k大了。得到存在性和最优性后,二分是安全舒适的;

 

1 #include
2 #include
3 #include
4 using namespace std; 5 const int N=251; 6 int n,m,k,mx,p[N<<1],b[N<<1],hd[N<<1],o,a[N][N]; 7 struct Edge{
int v,nt;}E[N*N]; 8 char gc(){ 9 static char *p1,*p2,s[1000000];10 if(p1==p2) p2=(p1=s)+fread(s,1,1000000,stdin);11 return (p1==p2)?EOF:*p1++;12 }13 int rd(){14 int x=0; char c=gc();15 while(c<'0'||c>'9') c=gc();16 while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=gc();17 return x;18 }19 void adde(int u,int v){20 E[o] = (Edge){v,hd[u]}; hd[u] = o++;21 E[o] = (Edge){u,hd[v]}; hd[v] = o++;22 }23 bool match(int u){24 for(int i=hd[u],v;i!=-1;i=E[i].nt){25 if(b[v=E[i].v]) continue; b[v]=1;26 if(!p[v]||match(p[v])) {27 p[v]=u,p[u]=v;28 return true;29 }30 }31 return false;32 }33 bool check(int mid){34 memset(hd,-1,sizeof(hd)); o=0;35 memset(p,0,sizeof(p));36 for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if(a[i][j]<=mid) adde(i,j+n);37 int ans = 0;38 for(int i=1;i<=n;i++){39 memset(b,0,sizeof(b));40 if(!p[i]&&match(i)) ans++;41 }42 return ans>=n-k+1;43 }44 int main()45 { freopen("bzoj4443.in","r",stdin);46 freopen("bzoj4443.out","w",stdout);47 n=rd(); m=rd(); k=rd();48 for(int i=1;i<=n;i++)49 for(int j=1;j<=m;j++) 50 mx = max(a[i][j]=rd(),mx);51 int l=1,r=mx;52 while(l
>1;54 if(check(mid)) r=mid;55 else l=mid+1;56 }57 printf("%d\n",l);58 return 0;59 }//by tkys_Austin;

 

 

 

转载于:https://www.cnblogs.com/Paul-Guderian/p/8692575.html

你可能感兴趣的文章
二叉树的遍历问题总结
查看>>
聊天室(C++客户端+Pyhton服务器)_1.框架搭设
查看>>
pytho logging
查看>>
Python内置函数(29)——help
查看>>
对Feature的操作插入添加删除
查看>>
git使用中的问题
查看>>
yaml文件 .yml
查看>>
phpcms 添加自定义表单 留言
查看>>
mysql 优化
查看>>
WCF 配置文件
查看>>
oracle导出/导入 expdp/impdp
查看>>
JAVA 技术类分享(二)
查看>>
Objective - C基础: 第四天 - 10.SEL类型的基本认识
查看>>
数据结构之查找算法总结笔记
查看>>
Android TextView加上阴影效果
查看>>
Android 音量调节
查看>>
windows上面链接使用linux上面的docker daemon
查看>>
每天一个小程序—0005题(批量处理图片大小)
查看>>
js-创建对象的几种方式
查看>>
JDK JRE Java虚拟机的关系
查看>>