Codeforces 704D Captain America 上下界最大流

题意

平面上有n个点,现在要把每个点染成红色或蓝色。把一个点染成蓝色需要b的代价,染成红色需要r的代价。同时有m个限制,每个限制形如某一行或某一列中,红点-蓝点数量的绝对值不能超过d。问最少需要多少代价。
n,m<=100000

分析

不难想到,我们可以把每个点先染成代价较大的颜色,然后考虑把尽量多的点改变成代价较小的颜色。
那么我们可以把每一行建一个点,每一列建一个点,点(x,y)看成从第x行往第y列连一条流量为1的边。
然后对于每个限制,可以看成是某一行或某一列染的颜色数量存在一个上下界,然后直接跑上下界最大流就好了。

上下界最大流就是先把可行流跑出来,然后把多出来的边和点都删掉,再跑一次最大流就好了。
这样做为什么是对的呢?因为跑完可行流后的残余网络是满足流量平衡的,而当我们把新加的点和边都删掉后,无论它怎么流,都是仍然满足流量平衡的。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>

typedef long long LL;

const int N=100005;
const LL inf=(LL)1e15;

int n,m,r,b,w[N],h[N],sw[N],sh[N],s,t,S,T,ns,nt,last[N*2],dis[N*2],cur[N*2],cnt,num[N],mn[N*2],mx[N*2];
LL deg[N*2];
struct edge{int to,next;LL c;}e[N*30];
std::queue<int> que;
struct data{int x,y;}a[N];

void addedge(int u,int v,LL c)
{
    e[++cnt].to=v;e[cnt].c=c;e[cnt].next=last[u];last[u]=cnt;
    e[++cnt].to=u;e[cnt].c=0;e[cnt].next=last[v];last[v]=cnt;
}

bool bfs()
{
    for (int i=s;i<=T;i++) dis[i]=0;
    while (!que.empty()) que.pop();
    dis[ns]=1;que.push(ns);
    while (!que.empty())
    {
        int u=que.front();que.pop();
        for (int i=last[u];i;i=e[i].next)
            if (e[i].c&&!dis[e[i].to])
            {
                dis[e[i].to]=dis[u]+1;
                if (e[i].to==nt) return 1;
                que.push(e[i].to);
            }
    }
    return 0;
}

LL dfs(int x,LL maxf)
{
    if (x==nt||!maxf) return maxf;
    int ret=0;
    for (int &i=cur[x];i;i=e[i].next)
        if (e[i].c&&dis[e[i].to]==dis[x]+1)
        {
            LL f=dfs(e[i].to,std::min(e[i].c,maxf-ret));
            e[i].c-=f;
            e[i^1].c+=f;
            ret+=f;
            if (maxf==ret) break;
        }
    return ret;
}

LL dinic()
{
    LL ans=0;
    while (bfs())
    {
        for (int i=s;i<=T;i++) cur[i]=last[i];
        ans+=dfs(ns,inf);
    }
    return ans;
}

int main()
{
    scanf("%d%d",&n,&m);
    scanf("%d%d",&r,&b);cnt=1;
    for (int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y),w[i]=a[i].x,h[i]=a[i].y;
    std::sort(w+1,w+n+1);int w1=std::unique(w+1,w+n+1)-w-1;
    std::sort(h+1,h+n+1);int h1=std::unique(h+1,h+n+1)-h-1;
    s=0;t=w1+h1+1;
    for (int i=1;i<=n;i++)
    {
        int x=std::lower_bound(w+1,w+w1+1,a[i].x)-w;
        int y=std::lower_bound(h+1,h+h1+1,a[i].y)-h;
        sw[x]++;sh[y]++;addedge(x,y+w1,1);num[i]=cnt;
    }
    for (int i=1;i<=w1+h1;i++) mn[i]=n,mx[i]=0;
    for (int i=1;i<=m;i++)
    {
        int ty,l,d;scanf("%d%d%d",&ty,&l,&d);
        if (ty==1)
        {
            int p=std::lower_bound(w+1,w+w1+1,l)-w;
            if (w[p]!=l||d>=sw[p]) continue;
            int l1=(sw[p]-d+1)/2,l2=sw[p]-l1;
            if (l1>l2) {puts("-1");return 0;}
            mx[p]=std::max(mx[p],l1);mn[p]=std::min(mn[p],l2);
        }
        else
        {
            int p=std::lower_bound(h+1,h+h1+1,l)-h;
            if (h[p]!=l||d>=sh[p]) continue;
            int l1=(sh[p]-d+1)/2,l2=sh[p]-l1;
            if (l1>l2) {puts("-1");return 0;}
            mx[p+w1]=std::max(mx[p+w1],l1);mn[p+w1]=std::min(mn[p+w1],l2);
        }
    }
    for (int i=1;i<=w1;i++) deg[s]-=mx[i],deg[i]+=mx[i],addedge(s,i,std::min(sw[i],mn[i])-mx[i]);
    for (int i=w1+1;i<=w1+h1;i++) deg[t]+=mx[i],deg[i]-=mx[i],addedge(i,t,std::min(sh[i-w1],mn[i])-mx[i]);
    int tcnt=cnt;S=t+1;T=t+2;
    addedge(t,s,inf);LL sum=0;
    for (int i=s;i<=t;i++)
        if (deg[i]<0) addedge(i,T,-deg[i]);
        else if (deg[i]>0) addedge(S,i,deg[i]),sum+=deg[i];
    ns=S;nt=T;
    if (dinic()!=sum) {puts("-1");return 0;}
    for (int i=tcnt+1;i<=cnt;i++) e[i].c=0;
    ns=s;nt=t;dinic();
    LL ans=0;
    for (int i=1;i<=n;i++) ans+=e[num[i]].c?std::min(b,r):std::max(b,r);
    printf("%I64d\n",ans);
    for (int i=1;i<=n;i++)
        if (e[num[i]].c) putchar(r>b?'b':'r');
        else putchar(r>b?'r':'b');
    return 0;
}
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 、4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。、可私 6信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 、4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。、可 6私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 、4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。、可私 6信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值