hdu6126 Give out candies

本文介绍了HDU 6126题目的解题思路,该题目涉及网络流算法。题解中提到,这是一道标准的网络流套路题,虽然解题者已经忘记了具体的套路。文章详细阐述了如何构建网络流图,并通过增加限制条件来适应题目需求。最后,提供了代码实现。
摘要由CSDN通过智能技术生成

链接

http://acm.hdu.edu.cn/showproblem.php?pid=6126

题解

网络流套路题(然而套路我早都忘光了)
( i , j ) (i,j) (i,j)表示第 i i i个人收到的糖果数量 ≥ j \geq j j
S S S连边到 ( i , 1 ) (i,1) (i,1),容量 ∞ \infin ( i , j ) (i,j) (i,j)连到 ( i , j + 1 ) ( j &lt; m ) (i,j+1)(j&lt;m) (i,j+1)(j<m),容量 1000 − w i j 1000-w_{ij} 1000wij,然后 ( i , m ) (i,m) (i,m)连到 T T T,容量 1000 − w i m 1000-w_{im} 1000wim
这张图的最小割就就对应没有任何限制的时候的( 1000 n − 1000n- 1000n答案),但是有限制 x − y ≤ z x-y\leq z xyz y ≥ x − z y\geq x-z yxz
那么对于点 ( x , j ) (x,j) (x,j),向 ( y , j − z ) (y,j-z) (y,jz) ∞ \infin 的边,如果 j − z &gt; m j-z&gt;m jz>m,那就向 T T T ∞ \infin 的边

代码

#include <bits/stdc++.h>
#define maxn 3000
#define maxe 100000
#define iinf 0x3f3f3f3f
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
int read(int x=0)
{
    int c, f(1);
    for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
    for(;isdigit(c);c=getchar())x=x*10+c-0x30;
    return f*x;
}
struct Graph2
{
    int head[maxn], next[maxe], to[maxe], w[maxe], c[maxe], tot;
    void clear(int N)
    {
        int i;
        for(i=1;i<=N;i++)head[i]=0;
        for(i=2;i<=tot;i++)next[i]=0;
        tot=1;
    }
    void add(int a, int b, int ww, int cc){to[++tot]=b;next[tot]=head[a];w[tot]=ww;c[tot]=cc;head[a]=tot;}
    void adde(int a, int b, int ww,int cc){add(a,b,ww,cc);add(b,a,-ww,0);}
}G;
struct ISAP
{
    int S, T, last[maxn], d[maxn], num[maxn], Exit;
    void init(int N)
    {
        for(int i=1;i<=N;i++)d[i]=num[i]=0;
        num[0]=N;
        Exit=0;
    }
    int dfs(Graph2& G, int pos, int in)
    {
        int flow=0, t;
        if(pos==T)return in;
        for(int &p=last[pos];p;p=G.next[p])
            if(G.c[p] and d[G.to[p]]+1==d[pos])
            {
                flow+= t=dfs(G,G.to[p],min(in-flow,G.c[p]));
                G.c[p]-=t, G.c[p^1]+=t;
                if(Exit or in==flow)return flow;
            }
        Exit=--num[d[pos]]==0;
        ++num[++d[pos]];
        last[pos]=G.head[pos];
        return flow;
    }
    int maxflow(Graph2& G)
    {
        int ans(0);
        while(!Exit)
        {
            auto f=dfs(G,S,iinf);
            if(f>10000)return -1;
            ans+=f;
        }
        return ans;
    }
}isap;
int N, M, K;
int main()
{
    int T(read()), i, j, ok;
    while(T--)
    {
        N=read(), M=read(), K=read();
        G.clear(N*M+10);
        isap.init(N*M+10);
        isap.S=N*M+9, isap.T=N*M+10;
        for(i=1;i<=N;i++)
        {
            for(j=1;j<=M;j++)
            {
                auto id=(i-1)*M+j;
                if(j<M)G.adde(id,id+1,0,1000-read());
                else G.adde(id,isap.T,0,1000-read());
                if(j==1)G.adde(isap.S,id,0,iinf);
            }
        }
        while(K--)
        {
            auto x=read(), y=read(), z=read();
            // x-y <= z
            // y >= x-z
            for(i=1;i<=M;i++)
            {
                auto a=(x-1)*M+i, b=(y-1)*M+i-z;
                if(1<=i-z and i-z<=M)G.adde(a,b,0,iinf);
                if(i-z>M)G.adde(a,isap.T,0,iinf);
            }
        }
        auto f=isap.maxflow(G);
        if(f==-1)cout<<-1<<endl;
        else cout<<-f+1000*N<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值