博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
bzoj 4443: [Scoi2015]小凸玩矩阵
阅读量:6428 次
发布时间:2019-06-23

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

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 149  Solved: 81
[][][]

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

题解:

  N个数中的第K大,就是第N-K+1小,这点要是没看见就毁了。设这个数为x,二分这个数,判断是否合法。

  判断合法的方法,N^2枚举矩阵中的每个数,如果这个a[i][j]数小于等于x,让i连一条到j,容量为1的边。因为要保证N个数的i,j各不相同,所以设行i为x集,列j为y集,所有边权均为1,做最大流,也就是二分图的最大匹配。如果跑出来的maxflow大于等于N-K+1,说明x满足条件。注意以上两个不等关系都是大于等于,因为要考虑这样一种情况,整个矩阵的数字都是1,第1小是1,第N小还是1。我被这个坑了好久。。。

1 /**************************************************************  2     Problem: 4443  3     User: __abcdef__  4     Language: C++  5     Result: Accepted  6     Time:216 ms  7     Memory:14640 kb  8 ****************************************************************/  9   10 #include
11 #include
12 #include
13 #include
14 #include
15 #include
16 #include
17 #include
18 using namespace std; 19 typedef long long LL; 20 const int inf=1e9,maxn=300; 21 int N,M,K,S,T,tot,MIN=inf,MAX; 22 int a[maxn][maxn],tmp[maxn][maxn]; 23 struct MAT{ 24 int x,y,v,f; 25 }mat[maxn*maxn]; 26 inline int cmp(const MAT & e,const MAT & w){ 27 return e.v
Q; 43 while(!Q.empty()) Q.pop(); 44 Q.push(S); dis[S]=1; 45 while(!Q.empty()){ 46 int x=Q.front(); Q.pop(); 47 for(int i=head[x];i;i=e[i].next){ 48 int y=e[i].to; 49 if(dis[y]==0&&e[i].rest){ 50 dis[y]=dis[x]+1; 51 Q.push(y); 52 } 53 } 54 } 55 if(dis[T]!=0) return true; 56 return false; 57 } 58 inline int DFS(int x,int flow){ 59 if(x==T) return flow; 60 int now=0,temp; 61 for(int i=head[x];i;i=e[i].next){ 62 int y=e[i].to; 63 if(dis[y]==dis[x]+1&&e[i].rest){ 64 temp=DFS(y,min(flow-now,e[i].rest)); 65 e[i].rest-=temp; 66 e[i^1].rest+=temp; 67 now+=temp; 68 if(now==flow) return flow; 69 } 70 } 71 if(!now) dis[x]=0; 72 return now; 73 } 74 75 inline int dinic(){ 76 int ans=0; 77 while(BFS()==true) ans+=DFS(S,inf); 78 return ans; 79 } 80 81 inline bool jud(int x){ 82 83 for(int i=1;i<=cnt+10;i++) e[i].to=e[i].rest=e[i].next=0; 84 memset(head,0,sizeof(head)); cnt=1; 85 S=0; T=N+M+1; 86 for(int i=1;i<=N;i++) Addedge(S,i,1);// S 连向 x集 权值为 1 87 for(int i=1;i<=M;i++) Addedge(N+i,T,1);//y集 连向 T 权值为 1 88 for(int i=1;i<=N;i++){ // x集 连向 y集 89 for(int j=1;j<=M;j++){ 90 if(tmp[i][j]<=x){ 91 Addedge(i,N+j,1); 92 } 93 } 94 } 95 int maxflow=dinic(); 96 if(maxflow>=N-K+1) return true; 97 else return false; 98 } 99 inline int find(int l,int r){100 if(l+1>=r){101 if(jud(l)==true) return l;102 else return r;103 }104 int mid=(l+r)>>1;105 if(jud(mid)==true) return find(l,mid);106 else return find(mid+1,r);107 }108 int main(){109 scanf("%d%d%d",&N,&M,&K);110 for(int i=1;i<=N;i++){111 for(int j=1;j<=M;j++){112 scanf("%d",&a[i][j]);113 mat[++tot].x=i; mat[tot].y=j; mat[tot].v=a[i][j];114 }115 }116 tot=0;117 sort(mat+1,mat+N*M+1,cmp);118 for(int i=1;i<=N*M;i++){119 if(mat[i].v!=mat[i-1].v) mat[i].f=++tot;120 else mat[i].f=tot;121 }122 for(int i=1;i<=N*M;i++){123 tmp[mat[i].x][mat[i].y]=mat[i].f;124 MIN=min(MIN,mat[i].f); MAX=max(MAX,mat[i].f);125 }126 int ggg=find(MIN,MAX);127 for(int i=1;i<=N;i++){128 for(int j=1;j<=M;j++){129 if(tmp[i][j]==ggg){130 printf("%d\n",a[i][j]);131 return 0;132 }133 }134 }135 return 0;136 }

 

转载于:https://www.cnblogs.com/CXCXCXC/p/5310443.html

你可能感兴趣的文章
java学习第一天1.2
查看>>
清空输入缓冲区的方法
查看>>
Yii2 项目优化小贴士
查看>>
UIScrollView的判断位置的属性如下:
查看>>
Applicatin Loader上传app步骤记录
查看>>
两种方法修改table表的内容
查看>>
张小龙莫慌 马化腾莫急 你们要好好的 微信还有时间
查看>>
一些常用软件静默安装参数(nsis,msi,InstallShield ,Inno)
查看>>
部署mimic版本的Ceph分布式存储系统
查看>>
Java缓冲流细节
查看>>
IOS中复制对象的用法及深拷贝和浅拷贝详解
查看>>
lfs
查看>>
Eclipse内存不够解决办法
查看>>
关于tbody js取法兼容。
查看>>
php 使用phpqrcode类生成带有logo的二维码 使logo不失真(透明)
查看>>
[CC]点云密度计算
查看>>
程序出错Program received signal:SIGKILL
查看>>
CATransition 动画处理视图切换
查看>>
[转载] 高等应用数学问题的matlab求解——第3章 微积分问题的计算机求解
查看>>
大整数比较大小
查看>>