您的位置:首页 > 其它

【bzoj4443】[Scoi2015]小凸玩矩阵

2016-04-07 21:54 267 查看
第K大也就是第n-K+1小,所以就可以的二分答案了 (江哥讲过一道类似题)

二分答案找出比当前答案小的数的位置的坐标,判断一下是否可以选出满足不在同一行同一列的n-K+1个数,然后就可以跑匈牙利了,对于一个坐标(x,y)如果满足a[x][y]≤a[x][y]当前答案,就把第x行向第y列连边,然后跑匈牙利判断最大匹配是否大于n-K+1

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#include<set>
using namespace std;

#define M 300
#define N 1000001

struct edge
{
int v,next;
}e[N<<1];
int head[N<<1];
int cnt;

int map[M][M];
int ly
,f
;

int n,m,k;
int l,r;
int maxn,tot,ans;

void link(int x,int y)
{
e[++cnt]=(edge){y,head[x]};
head[x]=cnt;
}

bool find(int d)
{
for (int i=head[d];i;i=e[i].next)
{
int t=e[i].v;
if (ly[t]!=tot)
{
ly[t]=tot;
if (!f[t] || find(f[t]))
{
f[t]=d;
return true;
}
}
}
return false;
}

int work(int x)
{
ans=cnt=0;
memset(head,0,sizeof(head));
memset(f,0,sizeof(f));
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
if (map[i][j]<=x)
link(i,j);
for (int i=1;i<=n;i++)
{
tot++;
ans+=find(i);
}
return ans>=k ? 1: 0;
}

int main()
{
scanf("%d%d%d",&n,&m,&k);
k=n-k+1;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
scanf("%d",&map[i][j]),maxn=max(maxn,map[i][j]);
l=1;
r=maxn;
while (l<r)
{
int m=l+r>>1;
if (work(m))
r=m;
else
l=m+1;
}
printf("%d\n",l);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: