mean

题目描述

NiroBC 是猫咪学堂一年级的新生,开学第一天,学堂组织了一场迎新会,在
迎新会上,猫咪们会互相赠送礼物。
一年级的新生共有 N 只猫咪,编号为 1 . . . N(包括 NiroBC 自己),其中有
M 对猫咪是在开学前就互相认识的。学堂规定,对于任意一对已经互相认识的
猫咪 u, v,要么 u 送 v 一份礼物,要么 v 送 u 一份礼物。
学堂知道猫咪们都十分抠门,所以希望安排一种送礼物的方案,使得送出礼
物最多的猫咪送出的礼物最少。

输入格式

第一行两个正整数 N, M,表示猫咪的数量和已经互相认识的猫咪的对数。
接下来 M 行,每行两个整数 u, v,表示 u, v 已经互相认识。数据保证 u ̸= v,
且同一个数对最多出现一次((u, v) 和 (v, u) 算作同一数对)。

输出格式

一个整数,表示送出礼物最多的猫咪最少需要送出几份礼物。

分析:

由于决策单调性,所以可以二分答案,而判定mid的合法性可以跑最大流,将个关系
当作一个点,源点与这些点相连,容量为1,将这些关系的点与此关系的两个点连一条
容量为1的边,最后将这些人的点与汇点连接一条容量为mid的边,跑出最大流,若等
于关系数m,则合法,否则不合法。

代码:

#include<cstdio>
#include<cctype>
#define min(a,b) (a<b?a:b)
#define out(x) printf("%d",x)
#define inf 0x3f3f3f3f
#define maxn 1000007
#define maxm 1000007

template <typename T> void in(T &x) {
    char ch=getchar();bool flag=0;
    while(ch>'9'||ch<'0') flag|=(ch=='-'),ch=getchar();
    x=ch-'0';ch=getchar();
    while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    if(flag) x=-x;
    return ;
}

int n,m,s,t,cnt=1,cur[maxn],head[maxn],d[maxn],q[maxn];
struct edge{
    int to,cost,nxt;
}e[maxm];

void link(int u,int v,int cost){
    e[++cnt].to=v;e[cnt].nxt=head[u];e[cnt].cost=cost;head[u]=cnt;
    e[++cnt].to=u;e[cnt].nxt=head[v];e[cnt].cost=0;head[v]=cnt;
}

bool bfs(){
    for(int i=0;i<=t;i++)
        cur[i]=head[i],d[i]=0;
    int ha=1,ta=1,now;
    d[s]=1;q[1]=s;
    while(ha<=ta){
        now=q[ha++];
        for(int i=head[now];i;i=e[i].nxt)
            if(!d[e[i].to]&&e[i].cost){
                d[e[i].to]=d[now]+1;
                q[++ta]=e[i].to;
                if(e[i].to==t) return 1;
            }
    }
    return 0;
}

int dfs(int u,int flow){
    if(u==t) return flow;
    int rest=flow;
    for(int w,i=cur[u];i;i=e[i].nxt){
        cur[u]=i;
        if(e[i].cost&&d[e[i].to]==d[u]+1){
            w=dfs(e[i].to,min(rest,e[i].cost));
            if(!w) { 
                d[e[i].to]=0;
                continue;
            }
            e[i].cost-=w;
            e[i^1].cost+=w;
            rest-=w;
            if(rest==0) return flow;
        }
    }
    if(rest==flow)d[u]=0;
    return flow-rest;
}

int maxflow=0;

void dinic(){
    int w;
    maxflow=0;
    while(bfs())
        while(w=dfs(s,inf)) maxflow+=w;
    return ;
}

void build(){
    in(n);in(m);
    s=0,t=n+m+5;
    for(int i=1,u,v;i<=m;i++){
        in(u);in(v);
        link(s,i,1);
        link(i,u+m,1);
        link(i,v+m,1);
    }
    for(int i=1;i<=n;i++)
        link(i+m,t,0);
    return ;
}

bool work(int x){
    for(int i=head[s];i;i=e[i].nxt){
        e[i].cost=1;
        e[i^1].cost=0;
    }
    for(int i=1;i<=m;i++)
        for(int to,j=head[i];j;j=e[j].nxt){
            to=e[j].to;
            if(to!=s){
                e[j].cost=1;
                e[j^1].cost=0;
            }
        }
    for(int i=m+1;i<=n+m;i++)
        for(int to,j=head[i];j;j=e[j].nxt){
            to=e[j].to;
            if(to==t){
                e[j].cost=x;
                e[j^1].cost=0;
            }
        }
    dinic();
    if(maxflow==m) return 1;
    return 0;
}

int main(){
    build();
    int l=1,ans=n,r=n,mid;
    while(l<=r){
        mid=(l+r)>>1;
        if(work(mid)) ans=mid,r=mid-1;
        else l=mid+1;
    }
    printf("%d",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ieqefcr/p/9833209.html