【bzoj4443】[Scoi2015]小凸玩矩阵 二分+二分图匹配

二分答案
判断是否能取出N-K+1个小于等于ans的数
但是能取出N-K+1个小于等于ans的数,不代表能取出K个大于等于ans的数呀
注意,最后得到的ans是最小的存在N-K个比它小的数的数

如果连最小的ans都取不到,那么更大的ans也取不到呀


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>
#define maxn 510

using namespace std;

struct yts
{
	int w;
	int x,y;
}q[100010];

int b[maxn][maxn];
int lk[maxn];
int a[maxn][maxn];
bool vis[maxn];
int n,m,num,k,tot;

bool find(int x)
{
	for (int i=1;i<=m;i++)
	  if (a[x][i] && !vis[i])
	  {
	  	vis[i]=1;
	  	if (!lk[i] || find(lk[i]))
	  	{
	  		lk[i]=x;
	  		return 1;
	  	}
	  }
	return 0;
}

bool check(int x)
{
	memset(lk,0,sizeof(lk));
	memset(a,0,sizeof(a));
	for (int i=1;i<=tot;i++) if (q[i].x!=q[x].x && q[i].y!=q[x].y && q[i].w<=q[x].w) a[q[i].x][q[i].y]=1;
	int ans=0;
	for (int i=1;i<=n;i++)
	{
		memset(vis,0,sizeof(vis));
		if (find(i)) ans++;
	}
	if (ans>=n-k) return 1; else return 0;
}

bool cmp(yts x,yts y)
{
	return x.w<y.w;
}

int main()
{
	scanf("%d%d%d",&n,&m,&k);
	for (int i=1;i<=n;i++)
	  for (int j=1;j<=m;j++)
	  {
	    scanf("%d",&a[i][j]);
	    q[++tot].w=a[i][j];q[tot].x=i;q[tot].y=j;
	  }
	sort(q+1,q+tot+1,cmp);
	int l=1,r=tot,ans=0;
	while (l<=r)
	{
		int mid=(l+r)/2;
		if (check(mid)) ans=mid,r=mid-1; else l=mid+1;
	}
	printf("%d\n",q[ans].w);
	return 0;
}



你可能感兴趣的:(【bzoj4443】[Scoi2015]小凸玩矩阵 二分+二分图匹配)