問題の説明
小さな正方形と小突起は、小さな凸状に小さい側の友人である\(M×N(N \当量M)\) 行列Aの、必要な数N小突起がマトリックスから選択され、ここで任意の二つ番号は、同じ行または同じ列にすることはできません。今小さな凸状の疑問、数N多数K-選出された最小数です。
入力形式
最初の行は三つの整数N、M、Kが読み出されます。
続いてN行、各行がm個、第i行の第j列の要素とj番目の数は、行列の行iを表し有する\(A_ {I、Jを} \) 。
出力フォーマット
出力は、N k個選択多数の最小値として行番号を含んでいます。
データ範囲
、データの20%を\(1 \ n型のLeq \のLeq M \ 1当量9 \)
、データの40%\(1 \ n型のLeq \のLeq M \のLeq 22 ,. 1 \ n型のLeq \のLeq 12 \です)
データの100%に\(1 \のLeq K \ n型のLeq \のLeq M \のLeq 250 ,. 1 \ A_のLeq {I、J} \ 1当量9 ^ 10 \)
リンク
解決
各行及び各列は二部グラフマッチングを制限する非常に類似している、一点のみが選択されていてもよいです。あなたはこの点で検討すると良いかもしれません。
まず、答えが単調に発見され、その後、第一中間半分は、マトリックスは、0未満がセットされている中間の数、中間に等しいか又はより大きい。次いで、マトリックスは、新しい隣接行列、最大ラン2部グラフマッチングとして生成することができます。ヒット数が以上であれば(N-MID + 1 \ \ ) 、説明を求めることができる(N-MID + 1 \ \ ) 上より(MID \)\の要件を満たすために多数、すなわち\(MID \)小;大きすぎる逆に。
コード
#include <iostream>
#include <cstdio>
#include <cstring>
#define N 252
using namespace std;
int n,m,k,i,j,g[N][N],a[N][N],match[N*N];
bool vis[N*N];
int read()
{
char c=getchar();
int w=0;
while(c<'0'||c>'9') c=getchar();
while(c<='9'&&c>='0'){
w=w*10+c-'0';
c=getchar();
}
return w;
}
bool dfs(int x)
{
for(int i=1;i<=m;i++){
if(g[x][i]&&!vis[n+i]){
vis[n+i]=1;
if(!match[n+i]||dfs(match[n+i])){
match[n+i]=x;
return 1;
}
}
}
return 0;
}
int hungary()
{
int ans=0;
for(int i=1;i<=n;i++){
if(!match[i]){
memset(vis,0,sizeof(vis));
if(dfs(i)) ans++;
}
}
return ans;
}
bool check(int x)
{
memset(match,0,sizeof(match));
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++) g[i][j]=(a[i][j]<=x);
}
if(hungary()>=n-k+1) return true;
return false;
}
int main()
{
int l=1,r=0,mid,ans;
n=read();m=read();k=read();
for(i=1;i<=n;i++){
for(j=1;j<=m;j++){
a[i][j]=read();
r=max(r,a[i][j]);
}
}
while(l<=r){
mid=(l+r)/2;
if(check(mid)) ans=mid,r=mid-1;
else l=mid+1;
}
printf("%d\n",ans);
return 0;
}