【题解】Luogu P1344 [USACO4.4]追查坏牛奶Pollutant Control

原题传送门

看到这种题,应该一眼就能知道考的是最小割

没错这题就是如此简单,跑两遍最大流(最小割=最大流),一次边权为题目所给,一次边权为1

还有一种优化,优化后只需跑一次最大流,把每条边的权值改成w*MOD+1(MOD为常数,珂以取八位质数233)

答案为maxflow/MOD和maxflow%MOD

基础版本

#include <bits/stdc++.h>
#define N 40
#define M 2005
#define inf 0x3f3f3f3f
#define getchar nc
using namespace std;
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
    register int x=0,f=1;register char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return x*f;
}
inline void write(register int x)
{
    if(!x)putchar('0');if(x<0)x=-x,putchar('-');
    static int sta[20];register int tot=0;
    while(x)sta[tot++]=x%10,x/=10;
    while(tot)putchar(sta[--tot]+48);
}
inline int Min(register int a,register int b)
{
    return a<b?a:b;
}
struct edge{
    int to,nxt,v;
}e[M];
int head[N],cnt=1;
inline void add(register int u,register int v,register int w)
{
    e[++cnt]=(edge){v,head[u],w};
    head[u]=cnt;
}
int n,m,s,t,maxflow=0;
int cur[N],dep[N],gap[N];
inline void bfs()
{
    memset(dep,-1,sizeof(dep));
    memset(gap,0,sizeof(gap));
    dep[t]=0;
    ++gap[dep[t]];
    queue <int> q;
    q.push(t);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(register int i=head[u];i;i=e[i].nxt)
        {
            int v=e[i].to;
            if(dep[v]!=-1)
                continue;
            q.push(v);
            dep[v]=dep[u]+1;
            ++gap[dep[v]];
        }
    }
}
inline int dfs(register int u,register int flow)
{
    if(u==t)
    {
        maxflow+=flow;
        return flow;
    }
    int used=0;
    for(register int i=cur[u];i;i=e[i].nxt)
    {
        cur[u]=i;
        int v=e[i].to;
        if(e[i].v&&dep[u]==dep[v]+1)
        {
            int tmp=dfs(v,Min(flow-used,e[i].v));
            if(tmp)
                e[i].v-=tmp,e[i^1].v+=tmp,used+=tmp;
        }
        if(used==flow)
            return used;
    }
    --gap[dep[u]++]==0?dep[s]=n+1:++gap[dep[u]];
    return used;
}
inline void ISAP()
{
    maxflow=0;
    bfs();
    while(dep[s]<=n)
    {
        memcpy(cur,head,sizeof(head));
        dfs(s,inf);
    }
}
int main()
{
    n=read(),m=read();
    s=1,t=n;
    for(register int i=1;i<=m;++i)
    {
        int u=read(),v=read(),w=read();
        add(u,v,w),add(v,u,0);
    }
    ISAP();
    write(maxflow),putchar(' ');
    for(register int i=2;i<=cnt;++i)
        e[i].v=i%2?0:1;
    ISAP();
    write(maxflow);
    return 0;
}

优化版本

#include <bits/stdc++.h>
#define N 40
#define M 2005
#define inf 123456789123456789LL
#define ll long long
#define mod 19260817LL
#define getchar nc
using namespace std;
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline ll read()
{
    register ll x=0,f=1;register char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return x*f;
}
inline void write(register ll x)
{
    if(!x)putchar('0');if(x<0)x=-x,putchar('-');
    static int sta[20];register int tot=0;
    while(x)sta[tot++]=x%10,x/=10;
    while(tot)putchar(sta[--tot]+48);
}
inline ll Min(register ll a,register ll b)
{
    return a<b?a:b;
}
struct edge{
    int to,nxt;
    ll v;
}e[M];
int head[N],cnt=1;
inline void add(register int u,register int v,register ll w)
{
    e[++cnt]=(edge){v,head[u],w};
    head[u]=cnt;
}
int n,m,s,t;
ll maxflow=0;
int cur[N],dep[N],gap[N];
inline void bfs()
{
    memset(dep,-1,sizeof(dep));
    memset(gap,0,sizeof(gap));
    dep[t]=0;
    ++gap[dep[t]];
    queue <int> q;
    q.push(t);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(register int i=head[u];i;i=e[i].nxt)
        {
            int v=e[i].to;
            if(dep[v]!=-1)
                continue;
            q.push(v);
            dep[v]=dep[u]+1;
            ++gap[dep[v]];
        }
    }
}
inline ll dfs(register int u,register ll flow)
{
    if(u==t)
    {
        maxflow+=flow;
        return flow;
    }
    ll used=0;
    for(register int i=cur[u];i;i=e[i].nxt)
    {
        cur[u]=i;
        int v=e[i].to;
        if(e[i].v&&dep[u]==dep[v]+1)
        {
            ll tmp=dfs(v,Min(flow-used,e[i].v));
            if(tmp)
                e[i].v-=tmp,e[i^1].v+=tmp,used+=tmp;
        }
        if(used==flow)
            return used;
    }
    --gap[dep[u]++]==0?dep[s]=n+1:++gap[dep[u]];
    return used;
}
inline void ISAP()
{
    maxflow=0;
    bfs();
    while(dep[s]<n)
    {
        memcpy(cur,head,sizeof(head));
        dfs(s,inf);
    }
}
int main()
{
    n=read(),m=read();
    s=1,t=n;
    for(register int i=1;i<=m;++i)
    {
        int u=read(),v=read(),w=read();
        add(u,v,w*mod+1),add(v,u,0);
    }
    ISAP();
    write(maxflow/mod),putchar(' '),write(maxflow%mod);
    return 0;
}

原文地址:https://www.cnblogs.com/yzhang-rp-inf/p/10357244.html

时间: 2024-11-09 01:56:13

【题解】Luogu P1344 [USACO4.4]追查坏牛奶Pollutant Control的相关文章

洛谷 P1344 [USACO4.4]追查坏牛奶Pollutant Control

题目描述 你第一天接手三鹿牛奶公司就发生了一件倒霉的事情:公司不小心发送了一批有三聚氰胺的牛奶.很不幸,你发现这件事的时候,有三聚氰胺的牛奶已经进入了送货网.这个送货网很大,而且关系复杂.你知道这批牛奶要发给哪个零售商,但是要把这批牛奶送到他手中有许多种途径.送货网由一些仓库和运输卡车组成,每辆卡车都在各自固定的两个仓库之间单向运输牛奶.在追查这些有三聚氰胺的牛奶的时候,有必要保证它不被送到零售商手里,所以必须使某些运输卡车停止运输,但是停止每辆卡车都会有一定的经济损失.你的任务是,在保证坏牛奶

[USACO4.4]追查坏牛奶Pollutant Control

https://www.luogu.org/problemnew/show/P1344 这道题很容易就可以看出是最小割=最大流. 但是要求出要割几条边就有些毒瘤了. ↓为废话 但orzn*inf后,蒟蒻我还是没有想出怎么回事 犹豫好久后,还是悄咪咪点开了题解......... ↑为废话 原来有一个经典的套路: 只需建图时将边权w=w*a+1(w为本来的边权,a为大于1000的数),这样我们能求得最大流ans,则最小割的值为ans/a,割的边数为ans%a. 因为最小割的边集中有w1+w2+w3…

USACO Section 4.4 追查坏牛奶Pollutant Control

http://www.luogu.org/problem/show?pid=1344 题目描述 你第一天接手三鹿牛奶公司就发生了一件倒霉的事情:公司不小心发送了一批有三聚氰胺的牛奶.很不幸,你发现这件事的时候,有三聚氰胺的牛奶已经进入了送货网.这个送货网很大,而且关系复杂.你知道这批牛奶要发给哪个零售商,但是要把这批牛奶送到他手中有许多种途径.送货网由一些仓库和运输卡车组成,每辆卡车都在各自固定的两个仓库之间单向运输牛奶.在追查这些有三聚氰胺的牛奶的时候,有必要保证它不被送到零售商手里,所以必须

luogu P2740 [USACO4.2]草地排水Drainage Ditches

P2740 [USACO4.2]草地排水Drainage Ditches 2017-09-17 题目背景 在农夫约翰的农场上,每逢下雨,贝茜最喜欢的三叶草地就积聚了一潭水.这意味着草地被水淹没了,并且小草要继续生长还要花相当长一段时间.因此,农夫约翰修建了一套排水系统来使贝茜的草地免除被大水淹没的烦恼(不用担心,雨水会流向附近的一条小溪).作为一名一流的技师,农夫约翰已经在每条排水沟的一端安上了控制器,这样他可以控制流入排水沟的水流量. 题目描述 农夫约翰知道每一条排水沟每分钟可以流过的水量,和

追查坏牛奶(最大流)

进入今天的正题,追查坏牛奶 思想的话不会人家的玄学求最小割的边数,于是自己想了个神奇的乱搞,先求出最大流,即最小割,然后枚举每条边看是否完全属于割集,然后将其永久去掉 然后将整个输出即可 #include<bits/stdc++.h> using namespace std; #define ll long long const int N=100010; const ll INF=0x7ffffffff; ll m,n,s,t,pre[N],head[N],cnt=1,last[N],dep

题解 luogu P1850 【换教室】

题解 luogu P1850 [换教室] 时间:2019.8.6 一晚上(约 3.5h 写完) 题目描述 对于刚上大学的牛牛来说,他面临的第一个问题是如何根据实际情况申请合适的课程. 在可以选择的课程中,有 \(2n\) 节课程安排在 \(n\) 个时间段上.在第 \(i\)(\(1 \leq i \leq n\))个时间段上,两节内容相同的课程同时在不同的地点进行,其中,牛牛预先被安排在教室 \(c_i\) 上课,而另一节课程在教室 \(d_i\) 进行. 在不提交任何申请的情况下,学生们需要

题解 luogu P5021 【赛道修建】

题解 luogu P5021 [赛道修建] 时间:2019.8.9 20:40 时间:2019.8.12 题目描述 C 城将要举办一系列的赛车比赛.在比赛前,需要在城内修建 \(m\) 条赛道. C 城一共有 \(n\) 个路口,这些路口编号为 \(1,2,\dots,n\),有 \(n-1\) 条适合于修建赛道的双向通行的道路,每条道路连接着两个路口.其中,第 \(i\) 条道路连接的两个路口编号为 \(a_i\) 和 \(b_i\),该道路的长度为 \(l_i\).借助这 \(n-1\) 条

USACO 4.4 Pollutant Control (网络流求最小割割集)

Pollutant ControlHal Burch It's your first day in Quality Control at Merry Milk Makers, and already there's been a catastrophe: a shipment of bad milk has been sent out. Unfortunately, you didn't discover this until the milk was already into your del

luogu 1344 追查坏牛奶(最小割)

第一问求最小割. 第二问求割边最小的最小割. 我们直接求出第二问就可以求出第一问了. 对于求割边最小,如果我们可以把每条边都附加一个1的权值,那么求最小割是不是会优先选择1最少的边呢. 但是如果直接把边的权值+1,这样求得的最小割就不是原来的最小割了,那是因为1会对原来的容量产生影响. 如果把每条边的权值都乘以一个很大的常数,再加上附加权值1,这样求出的最小割是不是显然也是原图的最小割呢. 那么最终的答案除以这个常数就是最小割的容量,最终的答案模这个常数就是最小割的最小割边数. # includ