小凸和小方是好朋友,小方給小凸一個N*M(N<=M)的矩陣A,要求小禿從其中選出N個數,其中任意兩個數字不能在同一行或同一列,現小凸想知道選出來的N個數中第K大的數字的最小值是多少。
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 }