Bubble Cup 13 - Finals [Online Mirror, unrated, Div. 1] B. Valuable Paper(二分+二分图最大匹配)

题目链接
分析:网络流的题做多了看到这个就明白啥意思了,题意很明显,就是建一个二分图求一个最大匹配,并且要求每条匹配边的最大值最小,而对于最大值最小就二分答案准没错,而考虑一下是否具有单调性,对于答案ans,对于任意大于ans的值val跑出来的完美匹配,所以是具有单调性的。
然后问题就被转换成了,若最大边不超过mid,是否存在完美匹配。所以问题就成了一个判定问题,考虑怎么解决这个判定问题,每次二分一个值mid,不通过值大于mid的边增广,这样跑出来的是否是完美匹配。问题就解决了。
每次求最大流时不要忘了清空边的流量。

#include<bits/stdc++.h>
#define PII pair<int,int>
#define x first
#define y second
#define MAIN main
using namespace std;
typedef long long LL;
const int INF=0x3f3f3f3f;
const int N=2e4+10;
struct edge
{
    int u,v,cap,flow,num;
    edge(int u=0,int v=0,int cap=0,int flow=0,int num=0):u(u),v(v),cap(cap),flow(flow),num(num){}
};
vector<edge>E;
vector<int>g[N];
void add(int u,int v,int cap,int num)
{
    E.push_back(edge(u,v,cap,0,num));
    E.push_back(edge(v,u,0,0,num));
    int m=E.size();
    g[u].push_back(m-2);
    g[v].push_back(m-1);
}
int n,m;
int vis[N],d[N],cur[N];
int bfs(int s,int t,int mid)
{
    memset(vis,0,sizeof(vis));
    queue<int>q;
    q.push(s);
    vis[s]=1;d[s]=0;
    while(!q.empty())
    {
        int u=q.front();q.pop();
        for(int i=0;i<(int)g[u].size();i++){
            edge &e=E[g[u][i]];
            if(e.num>mid) continue;
            int v=e.v;
            if(!vis[v]&&e.cap>e.flow){
                vis[v]=1;
                d[v]=d[u]+1;
                q.push(v);
            }
        }
    }
    return vis[t];
}
int dfs(int s,int t,int a,int mid)
{
    if(s==t||a==0) return a;
    int flow=0,f;
    for(int &i=cur[s];i<(int)g[s].size();i++){
        edge &e=E[g[s][i]];
        if(e.num>mid) continue;
        int v=e.v;
        if(d[v]==d[s]+1&&(f=dfs(v,t,min(a,e.cap-e.flow),mid))>0){
            flow+=f;
            e.flow+=f;
            E[g[s][i]^1].flow-=f;
            a-=f;
            if(a==0) break;
        }
    }
    return flow;
}
int max_flow(int s,int t,int mid)
{
    int flow=0;
    while(bfs(s,t,mid))
    {
        memset(cur,0,sizeof(cur));
        flow+=dfs(s,t,INF,mid);
    }
    return flow;
}
int s,t;
bool judge(int mid)
{
    for(int i=0;i<(int)E.size();i++) E[i].flow=0;
    int flow=max_flow(s,t,mid);
    if(flow==n) return true;
    return false;
}
int MAIN()
{
    scanf("%d%d",&n,&m);
    s=0,t=2*n+1;
    for(int i=1;i<=m;i++){
        int u,v,d;
        scanf("%d%d%d",&u,&v,&d);
        add(u,v+n,1,d);
    }
    for(int i=1;i<=n;i++){
        add(s,i,1,0);
        add(i+n,t,1,0);
    }
    int l=0,r=1e9,mid,ans=-1;
    while(l<=r)
    {
        mid=(l+r)>>1;
        if(judge(mid)) r=mid-1,ans=mid;
        else l=mid+1;
    }
    printf("%d\n",ans);
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值