BZOJ 2502: 清理雪道

本文介绍了一种求解有源汇有上下界的最小流问题的算法实现,并通过具体代码展示了如何利用图论中的网络流理论来解决此类问题。该算法通过引入额外的虚拟节点来确保流满足指定的上下界条件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

有源汇有上下界最小流

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<queue>
#define INF 2e9
#define N 110
#define M 12500
using namespace std;
 
int read()
{
    int a=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){a=a*10+c-'0';c=getchar();}
    return a*f;
}
 
struct edge{int to,next,v;}e[M*2];
int n,m,cnt,sum,s,t,ss,tt;
int a[N],d[N],head[N],cur[N];
 
void add(int x,int y,int v)
{
    e[cnt].next=head[x],e[cnt].to=y,e[cnt].v=v;
    head[x]=cnt++;
    e[cnt].next=head[y],e[cnt].to=x,e[cnt].v=0;
    head[y]=cnt++;
}
 
int bfs()
{
    queue<int>q;
    memset(d,-1,sizeof(d));
    q.push(ss),d[ss]=0;
    while(!q.empty())
    {
        int x=q.front();q.pop();
        if(x==tt) {memcpy(cur,head,sizeof(cur));return 1;}
        for(int i=head[x];i!=-1;i=e[i].next)
            if(d[e[i].to]==-1&&e[i].v)
            {
                d[e[i].to]=d[x]+1;
                q.push(e[i].to);
            }
    }
    return 0;
}
 
int dfs(int x,int a)
{
    if(x==tt||!a) return a;
    int flow=0,f;
    for(int &i=cur[x];i!=-1;i=e[i].next)
        if(d[e[i].to]==d[x]+1&&(f=dfs(e[i].to,min(a,e[i].v)))>0)
        {
            e[i].v-=f;
            e[i^1].v+=f;
            flow+=f;
            a-=f;
            if(!a) break;
        }
    if(!flow) d[x]=-1;
    return flow; 
}
 
int dinic()
{
    int res=0;
    while(bfs())
        res+=dfs(ss,INF);
    return res;
}
 
int main()
{
    n=read();
    s=0,t=n+1,ss=n+2,tt=n+3;
    memset(head,-1,sizeof(head));
    for(int i=1;i<=n;++i)
        add(s,i,INF),add(i,t,INF);
    for(int i=1,m;i<=n;++i)
    {
        m=read();
        while(m--)
        {
            int j=read();
            add(i,j,INF);	//每个地方至少去一次即下界为1
            --a[i],++a[j];
        }
    }
    for(int i=1;i<=n;++i)
        if(a[i]>0)
            sum+=a[i],add(ss,i,a[i]);
        else if(a[i]<0)
            add(i,tt,-a[i]);
    add(t,s,INF);
    sum-=dinic();
    sum=e[head[t]^1].v;
    head[s]=e[head[s]].next,head[t]=e[head[t]].next;
    ss=t,tt=s;
    printf("%d\n",sum-dinic());
    return 0;
}

偷偷水一篇
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值