您的位置:首页 > 其它

BZOJ4443(Scoi2015)[小凸玩矩阵]--二分+二分图最大匹配

2017-06-29 20:34 501 查看
【链接】

bozj4443

【题目大意】

给你一个n*m的矩阵,选出n个数,且任意两个数字不能再同一行或同一列,求n个数中第K大的最小值。

【解题报告】

初看此题类似二分图最大匹配,但是直接刷又好像不行。因为这题是求最大值的最小值,所以就又想到二分,二分枚举什么呢?当然是枚举最小值x,再将矩阵中小于等于x的建边,最后判断是否可以从符合的数中选出n-k+1个数。(ps:因为是第K大所以是要选出n-k+1个数),这样就是二分+二分图最大匹配了。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=255,maxm=62505,INF=((1<<30)-1)*2+1;
int n,m,K,L,R,tot,a[maxn][maxn],who[maxn],lnk[maxn],son[maxm],nxt[maxm];
bool vis[maxn];
inline int Read()
{
int res=0;
char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9') res=res*10+ch-48,ch=getchar();
return res;
}
void Add(int x,int y)
{
son[++tot]=y; nxt[tot]=lnk[x]; lnk[x]=tot;
}
bool Find(int x)
{
if (vis[x]) return 0;
vis[x]=1;
for (int j=lnk[x]; j; j=nxt[j])
if (!who[son[j]]||Find(who[son[j]])) {who[son[j]]=x; return 1;}
return 0;
}
bool Check(int x)
{
memset(lnk,0,sizeof(lnk));
memset(who,0,sizeof(who));
int sum=0; tot=0;
for (int i=1; i<=n; i++)
for (int j=1; j<=m; j++)
if (a[i][j]<=x) Add(i,j);
for (int i=1; i<=n; i++)
{
memset(vis,0,sizeof(vis));
sum+=Find(i);
}
return sum>=n-K+1;
}
int main()
{
freopen("4443.in","r",stdin);
freopen("4443.out","w",stdout);
n=Read(); m=Read(); K=Read(); L=INF; R=0;
for (int i=1; i<=n; i++)
for (int j=1; j<=m; j++) a[i][j]=Read(),L=min(L,a[i][j]),R=max(R,a[i][j]);
while (L<=R)
{
int mid=(R-L>>1)+L;
if (Check(mid)) R=mid-1; else L=mid+1;
}
printf("%d",L);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: