匈牙利算法+二分答案 BZOJ 4443 小凸玩矩阵 SCOI 2015 题解

来源:互联网 发布:知乎痴情叔被骂 编辑:程序博客网 时间:2024/05/16 08:34

题目:

https://vjudge.net/problem/HYSBZ-4443


小凸和小方是好朋友,小方给小凸一个N*M(N<=M)的矩阵A,要求小秃从其中选出N个数,其中任意两个数字不能在同一行或同一列,现小凸想知道选出来的N个数中第K大的数字的最小值是多少。
这道题看到N个数中的第K大的数中的最小值,很容易想到要用二分答案(求解最大值最小),任意两个数字不能在同一行同一列,很容易想到二分图匹配(还记得那道矩阵炸弹题吗),所以显然就先找出所有里面最大的数,然后二分答案即可,用匈牙利算法来进行判断,然后改变l和r,最后输出l即可


#include<cstdio>#include<iostream>#include<cstring>#define MAXN 1000000+10#define MINN 300+10using namespace std;struct Line{    int from,to;    int next;}line[MAXN];int a[MINN][MINN]; int head[MAXN],tail,n,m,k,maxn;int girl[MAXN];bool used[MAXN];int feedin(){    int x=0,f=1; char c=getchar();    while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=getchar();    return f*x;} void add_line(int from,int to){    tail++;    line[tail].from=from;    line[tail].to=to;    line[tail].next=head[from];    head[from]=tail;}bool find(int x){    for(int i=head[x];i;i=line[i].next){        int v=line[i].to;        if(!used[v]){            used[v]=true;            if(girl[v]==-1||find(girl[v])){                girl[v]=x;                return true;            }        }    }    return false;}bool solve(int x){    memset(head,0,sizeof(head));    int cnt=0;tail=0;    for(int i=1;i<=n;i++){        for(int j=1;j<=m;j++){            if(a[i][j]<=x) add_line(i,j);        }    }    memset(girl,-1,sizeof(girl));    for(int i=1;i<=n;i++){        memset(used,false,sizeof(used));        if(find(i)) cnt++;    }    return cnt>=k;}int main(){    n=feedin();m=feedin();k=feedin();k=n-k+1;     for(int i=1;i<=n;i++){        for(int j=1;j<=m;j++){            maxn=max(maxn,a[i][j]=feedin());        }    }     int l=1,r=maxn;    while(l!=r){        int mid=l+r>>1;        if(solve(mid)) r=mid;        else l=mid+1;    }    cout<<l;    return 0;}

这里写图片描述

阅读全文
0 0
原创粉丝点击