BZOJ4443 小凸玩矩阵

来源:互联网 发布:linux fifo 编辑:程序博客网 时间:2024/05/16 03:56

二分图最大匹配

题目传送门

二分枚举第K大的数,满足的条件为选出的小于等于当前枚举到的数(num)的个数大于等于n-K+1。
判断方法就是对于每一个a[i][j]<=num建一条i到j的单向边,然后愉快的找增广路就可以啦。

AC代码:

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;struct edge{    int next;    int to;};int a[255][255];int h[255],who[255];edge ed[200000];bool f[255];int n,m,k,mi=0x7fffffff,ma,K;void create(int x,int y){    K++;    ed[K].next=h[x];    ed[K].to=y;    h[x]=K;}bool dfs(int x){    if (f[x]) return false;    f[x]=true;    for (int j=h[x];j;j=ed[j].next)        if (!who[ed[j].to]||dfs(who[ed[j].to])){            who[ed[j].to]=x;            return true;        }    return false;}bool pd(int num){    memset(h,0,sizeof(h));    K=0;    for (int i=1;i<=n;i++)        for (int j=1;j<=m;j++)            if (num>=a[i][j])                create(i,j);    int sum=0;    memset(who,0,sizeof(who));    for (int i=1;i<=n;i++){        memset(f,false,sizeof(f));        if (dfs(i))            sum++;    }    if (sum<k) return false;    return true;}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",&a[i][j]);            mi=min(mi,a[i][j]);            ma=max(ma,a[i][j]);        }    while (mi<=ma){        int mid=(mi+ma)/2;        if (pd(mid)) ma=mid-1;        else mi=mid+1;     }    printf("%d",mi);    return 0;}
原创粉丝点击