bzoj4443[Scoi2015]小凸玩矩陣

4443: [Scoi2015]小凸玩矩陣

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1460  Solved: 685
[Submit][Status][Discuss]

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^9php

二分答案轉化成斷定性問題
K大即n-K+1小
若是對於一個數x,有一種方案使得選出來<=x的數的個數 >n-k+1
知足單調性,因此能夠二分答案c++

接下來怎麼考慮使選出來的方案的知足條件
貪心,<=x的數越多越好
每行每列只能選一個數,經典的二分圖匹配模型spa

能夠經過離散來使二分的次數減小code

 

 1 #include<bits/stdc++.h>
 2 #define N 255 
 3 using namespace std;
 4 int n,m,K,cnt,tot,bl[N*2],vis[N*2],hd[N],a[N][N],b[N*N];
 5 struct edge{int v,next;}e[N*N];
 6 void adde(int u,int v){
 7     e[++tot].v=v;
 8     e[tot].next=hd[u];
 9     hd[u]=tot;
10 }
11 
12 bool dfs(int u){
13     //if(vis[u])return 0;vis[u]=1;
14     for(int i=hd[u];i;i=e[i].next){
15         int v=e[i].v;
16         if(vis[v])continue;vis[v]=1;
17         if(!bl[v]||dfs(bl[v])){
18             bl[v]=u;
19             return 1;
20         }
21     }
22     return 0;
23 }
24 
25 inline bool check(int x){
26     tot=0;memset(hd,0,sizeof(hd));
27     memset(bl,0,sizeof(bl));
28     for(int i=1;i<=n;i++)
29     for(int j=1;j<=m;j++)
30     if(a[i][j]<=x)adde(i,j+n);
31     int ret=0;
32     for(int i=1;i<=n;i++){
33         memset(vis,0,sizeof(vis));
34         if(dfs(i))ret++;
35     }
36     return ret>=K;
37 }
38 
39 int main(){
40     scanf("%d%d%d",&n,&m,&K);K=n-K+1;
41     for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
42     scanf("%d",&a[i][j]),b[++cnt]=a[i][j];
43     sort(b+1,b+1+cnt);
44     int len=unique(b+1,b+1+cnt)-b-1;
45     for(int i=1;i<=n;i++)
46     for(int j=1;j<=m;j++)
47     a[i][j]=lower_bound(b+1,b+1+len,a[i][j])-b;
48     int l=1,r=len,mid,ans;
49     while(l<=r){
50         mid=(l+r)>>1;
51         if(check(mid))r=(ans=mid)-1;
52         else l=mid+1;
53     }
54     printf("%d\n",b[ans]);
55     return 0;
56 }
相關文章
相關標籤/搜索