虽然这是一个二分图最大匹配,但是我匈牙利写挂了。
我太弱了。
好了不瞎扯牛逼了,这个题这么搞:
首先题目就告诉你求第k大最小。
首先这就让人瑟瑟发抖。。。。第k大诶,这种出了就是难题。
但凡事总有意外。
我们知道。这个行列单一模型是二分图常见模型。
zjoi2007矩阵游戏。开山鼻祖,可以玩玩。
还有World Final 2017 碟中谍(Mision Impossible)Wf的第四简单的题,但是做对四个怕不是也就前50了。
就是一个矩阵从二维到三维用贪心和匈牙利就好了。但是我太弱了写不来匈牙利于是写的二分图带权匹配。
好的,我们考虑二分。
这实际不难想到。
SCOI2014方伯伯运椰子:残量网络上用消圈定理来验证分数规划。
ZJOI2010贪吃的老鼠:构建网络流模型二分查找满足老鼠吃光的最小代价。
近年来单考网络流的省份不多了。大概还有CQSTC坚持吧。
但是CQOI2014危桥可真不是单一的网络流,这个验证证明很繁琐。
还有一种恶心的题:
以CQOI2010分金币和HAOI2008糖果传递为首。
他们太像网络流了。
乍一看和24题的负载平衡一模一样实际上这是一个数论推导。
随便列几个网络流的题吧:
POI2005-KOS唯一的槽点是他不是二分但却写了个二分一样的题面。
SHSTC2002 舞会这是个错题,所以只能跑匈牙利。
NOI2009 植物大战僵尸 最大权闭合图,当年压轴题要top缩环卡tarjan
ZJOI2010 网络扩容 开山的第一个扩容类网络流题(所以浙江牛逼啊)
ZJOI2009 狼和羊的故事 水题一道,最小割就好了。
SCOI2007 质朴的SCSTC时代的题还是UESTC的亲启题啊,水的一匹。
ZJOI2009 可以归为水题。
SCOI2007 修车。那一年考了两个网络流,修车很经典,难在拆k个点上
NOI2012 美食节,三年过去了,信息学就考的辣么难了,这是和修车一模一样的题,但是要动态开点。
还有就是24题啦。
实际上还有不少ACM的但是记不起出处了,下次有空更新!!(*^▽^*)
SCOI2015的那个代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
#define N 300*300
#define INF (int)1e9+7
#define ll int
inline void read(ll &x){
x=0;
ll f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
x*=f;
}
struct Front_star{
int u,v,w,nxt;
}e[N*2];
int cnt=1;
int first[N]={0};
void addedge(int u,int v,int w){
cnt++;
e[cnt].u=u;
e[cnt].v=v;
e[cnt].w=w;
e[cnt].nxt=first[u];
first[u]=cnt;
}
void add(int u,int v,int w){
addedge(u,v,w);
addedge(v,u,0);
}
void clr(){
memset(first,0,sizeof(first));
cnt=1;
}
int a[300][300]={0};
int n,m,k;
int S=0;
int T=801;
void build(int minsum){
for(int i=1;i<=n;i++){
add(S,i,1);
}
for(int j=1;j<=m;j++){
add(j+n,T,1);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i][j]<=minsum){
add(i,j+n,1);
}
}
}
}
int d[N]={0};
bool bfs(){
queue<int> q;
memset(d,-1,sizeof(d));
d[S]=1;
q.push(S);
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=first[x];i;i=e[i].nxt){
int v=e[i].v;
if(e[i].w&&d[v]==-1){
d[v]=d[x]+1;
q.push(v);
}
}
}
return d[T]!=-1;
}
int dfs(int st,int ed,int nowdat){
int dat=0;
if(st==ed){
return nowdat;
}
for(int i=first[st];i;i=e[i].nxt){
int v=e[i].v;
if(d[v]==d[st]+1&&e[i].w){
int now=min(nowdat-dat,e[i].w);
now=dfs(v,ed,now);
dat+=now;
e[i].w-=now;
e[i^1].w+=now;
if(nowdat==dat){
return dat;
}
}
}
if(!dat){
d[st]=-2;
}
return dat;
}
bool check(int sum){
int ans=0;
while(bfs()){
ans+=dfs(S,T,INF);
}
// cout<<ans<<endl;
if(ans>=n-sum+1){
return true;
}
else{
return false;
}
}
int ans;
int main(){
read(n);
read(m);
read(k);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
read(a[i][j]);
}
}
int l=0;
int r=(int)INF;
while(l<=r){
int mid=(l+r)/2;
// cout<<mid<<" ";
clr();
build(mid);
if(check(k)){
ans=mid;
r=mid-1;
}
else{
l=mid+1;
}
}
cout<<ans<<endl;
}