4443: [Scoi2015]小凸玩矩阵

4443: [Scoi2015]小凸玩矩阵Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 1954 Solved: 937
[Submit][Status][Discuss]

Description

小凸和小方是好朋友,小方给小凸一个N*M(N<=M)的矩阵A,要求小秃从其中选出N个数,其中任意两个数字不能在同一行或同一列,现小凸想知道选出来的N个数中第K大的数字的最小值是多少。

Input

第一行给出三个整数N,M,K

接下来N行,每行M个数字,用来描述这个矩阵

Output

如题

Sample Input

3 4 2
1 5 6 6
8 3 4 3
6 8 6 3

Sample Output

3

HINT

1<=K<=N<=M<=250,1<=矩阵元素<=10^9


...心态崩了

把行和列拆开然后就可以二分图匹配

然后就没了


#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<cstring>
#define M 1000000
using namespace std;

int a[M],d[M],i,m,n,j,k,ver[M],edge[M],head[M],nex[M],cnt=1,s,t,p,ans,x,y,cost[M],r,l=0x3f3f3f3f,cur[M];
queue <int>q;

inline void add(int x,int y,int z)
{
    ver[++cnt]=y; nex[cnt]=head[x]; head[x]=cnt; edge[cnt]=1; cost[cnt]=z;
    ver[++cnt]=x; nex[cnt]=head[y]; head[y]=cnt; edge[cnt]=0; cost[cnt]=z;
}

bool bfs(int z)
{
    memset(d,0,sizeof(d));
    for(i=0;i<=t;i++) cur[i]=head[i];
    while(q.size()) q.pop();
    q.push(0); d[0]=1;
    while(q.size())
    {
        int x=q.front(); q.pop();
        for(int i=head[x];i;i=nex[i])
        if(edge[i] && !d[ver[i]] && cost[i]<=z) 
        {
            q.push(ver[i]);
            d[ver[i]]=d[x]+1;
            if(ver[i]==t) return 1;
        }
    }
    return 0;
}

int dinic(int x,int flow,int z)
{
    int re=flow;
    if(x==t) return flow;
    if(!flow) return 0;
    for(int i=cur[x];i;i=nex[i])
    if(edge[i]==1 && d[ver[i]]==d[x]+1 && cost[i]<=z)
    {
        cur[x]=i;
        int s=dinic(ver[i],min(re, edge[i]),z);
        if(!s) d[ver[i]]=0;
        edge[i]-=s; edge[i^1]+=s;
        re-=s;
        if(!re) break;
    }
    return flow-re;
}

bool check(int x)
{
    int ans=0;
    while(bfs(x)) 
        while(s=dinic(0,0x3f3f3f3f,x)) ans+=s;
    for(int i=1;i<=cnt;i++) if(!(i&1)) edge[i]=1; else edge[i]=0;
    if(ans>=n-k+1) return 1;
    return 0;
}

int erfen()
{
    int tmp=r;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(check(mid)) tmp=mid, r=mid-1;
        else l=mid+1;
    }
    return tmp;
}


int main()
{
    scanf("%d%d%d",&n,&m,&k);
    t=n+m+1;
    for(i=1;i<=n;i++) add(0,i,0);
    for(i=1;i<=m;i++) add(n+i,t,0);
    for(i=1;i<=n;i++)
        for(j=1;j<=m;j++)
        {
            scanf("%d",&s);
            add(i,n+j,s);   
            r=max(r,s);
            l=min(l,s);
        }
        
    printf("%d",erfen());
}

猜你喜欢

转载自www.cnblogs.com/ZUTTER/p/10040439.html