首页 > 其他分享 >神奇脑洞题解——USACO追查坏牛奶(CSGO894)

神奇脑洞题解——USACO追查坏牛奶(CSGO894)

时间:2022-11-15 20:45:11浏览次数:71  
标签:cnt val int 题解 CSGO894 layer USACO 流量 head

COGS的这一题是超级满配版本

比洛谷的要强力的多:894. 追查坏牛奶 - COGS

额外要求是:求出最小割流量,同时求出割边最小,同时字典序最小的方案

输出割掉的边

最小割流量好求,最小割边的数量也好求,但同时确定哪条边不太好弄,因为存在方法互斥

首先:最小割流量就是跑最大流的结果

求最小割边的数量,需要在刚刚跑完最大流的网络上

把所有的满流边流量重新标记为1,不满流的重新标记为INF

在新的网络上跑一次最大流

这个时候得到的流量就是最小割边的数量

正确性:

满流边一定是某条流量通路的瓶颈路(虽然不一定是唯一瓶颈路)

把满流的边标记成1去跑增广路

得到的结果就是没有公共边的流量通路的条数(因为公共边只允许通过1点流量被计算一次)

那么就给这这些流量通路每个断开一条边即可(如果存在公共边先断开公共边)

如何求最小字典序的方案:

在最小割的情况下

首先要记住,我们一定是优先断开边权最大的必须满流边(删去这条边后,重新对整个网络跑最大流,最大流量会减小这个边的边权那么多(也就是这条边的传递作用无可替代))

那么找最小字典序方案也出来了:在正常的图上,先跑一次最大流

然后枚举所有边(首先把边按照边权(大到小)-字典序(小到大)两个关键字排序)

先复原整个网络到未增广形态

然后尝试删去这条边,看最大流结果减少的是否是这条边流量那么多

如果是,说明这是关键边,记录这条边会被删除(贪心保证了删除的边数目最少,因为这条边满流,不删它就要删和它在同一支流的多条边) 把这条边永久性删除,并将最大流的结果减小(该边的流量)那么多

这就导致你需要先用正常的边权跑DINIC,再用1和INF的边权跑DINIC,再用正常的边权去找应当被删除的边

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#define int long long int
using namespace std;
const int N = 100, M = 40000;
int head[N], val[M], to[M], nxt[M],vals[M],id[M];
int layer[N],cnt=1,n,m,S,T;
void ADD(int x, int y, int v,int idx)
{
    to[++cnt] = y;
    val[cnt] = v;
    nxt[cnt] = head[x];
    head[x] = cnt;
    vals[cnt] = v;
    id[cnt] = idx;
    to[++cnt] = x;
    val[cnt] = 0;
    nxt[cnt] = head[y];
    head[y] = cnt;
    vals[cnt] = 0;
    id[cnt] = idx;
}
bool BFS()
{
    queue<int> q;
    memset(layer, 0, sizeof(layer));
    q.push(S);
    layer[S] = 1;
    while (q.size())
    {
        int now = q.front();
        q.pop();
        for (int i = head[now]; i; i = nxt[i])
        {
            int y = to[i];
            if (layer[y] || !val[i])
                continue;
            layer[y] = layer[now] + 1;
            q.push(y);
        }
    }
    if (layer[T])
        return 1;
    return 0;
}
int Update(int x, int flow)
{
    if (x == T)
    {
        return flow;
    }
    int rest = flow;
    for (int i = head[x]; i; i = nxt[i])
    {
        int y = to[i];
        if (layer[y] != layer[x] + 1 || !val[i])
            continue;
        int k = Update(y, min(rest, val[i]));
        if (!k)
        {
            layer[y] = 0;
            continue;
        }
        rest -= k;
        val[i] -= k;
        val[i ^ 1] += k;
    }
    return flow - rest;
}
int Dinic()
{
    int kel,maxflow=0;
    while (BFS())
    {
        while (kel = Update(S, 0x3f3f3f3f))
        {
            //cout << "S";
            maxflow += kel;
        }
    }
    return maxflow;
}
void Change1()
{
    for (int i = 2; i <= cnt; i += 2)
    {
        if (val[i])
        {
            val[i] = 0x3f3f3f3f;
            val[i ^ 1] = 0;
        }
        else
        {
            val[i] = 1;
            val[i ^ 1] = 0;
        }
    }
}
struct EDGE
{
    int x, y, v,ids;
};
EDGE e[M];
bool Function(EDGE A, EDGE B)
{
    if (A.v == B.v)
        return A.ids < B.ids;
    return A.v > B.v;
}
signed main()
{
    freopen("milk6.in", "r", stdin);
    freopen("milk6.out", "w", stdout);
    scanf("%lld%lld", &n, &m);
    int a1, a2, a3;
    for (int i = 1; i <= m; i++)
    {
        scanf("%lld%lld%lld", &a1, &a2, &a3);
        e[i].x = a1;
        e[i].y = a2;
        e[i].v = a3;
        e[i].ids = i;
        //ADD(a1, a2, a3);
    }
    sort(e + 1, e + 1 + m,Function);
    for (int i = 1; i <= m; i++)
    {
        ADD(e[i].x, e[i].y, e[i].v, e[i].ids);
    }
    S = 1;
    T = n;
    int MINCOST = Dinic();
    Change1();
    int MINLINE = Dinic();
    memcpy(val, vals, sizeof(val));
    int anss[M], tot = 0;
    printf("%lld %lld\n", MINCOST, MINLINE);
    for (int i = 2; i <= cnt; i+=2)
    {
        int STD = val[i];
        val[i] = 0;
        val[i ^ 1] = 0;
        int SDS = Dinic();
        if (SDS== MINCOST - STD)
        {
            anss[++tot] = id[i];
            MINCOST-=STD;
            vals[i] = 0;
            vals[i ^ 1] = 0;
        }
        memcpy(val, vals, sizeof(val));
        if (MINCOST == 0)
            break;
    }
    sort(anss + 1, anss + 1 + tot);
    for (int i = 1; i <= tot; i++)
    {
        printf("%lld\n", anss[i]);
    }
    return 0;
}

 

标签:cnt,val,int,题解,CSGO894,layer,USACO,流量,head
From: https://www.cnblogs.com/XLINYIN/p/16893761.html

相关文章

  • 【题解】[模拟赛20221115] Tree
    模拟赛20221115Tree|CQNK\(O(m*n*2^n)\)很好做,但是本题有更优秀的做法:在此记录复杂度\(O(n*2^n)\)的做法。考虑从后往前dp,设dp状态\(f_{s,0/1}\)分别表示在填......
  • 题解 ARC001C【パズルのお手伝い】
    postedon2021-01-1118:20:37|under题解|source前言这道题与八皇后很像,可以做完八皇后再来做这道题。如果你\(\color{white}\colorbox{red}{WA}\)了,请检查你有......
  • 题解 UVA12265【贩卖土地 Selling Land】
    postedon2022-09-2414:33:29|under题解|sourceproblem一个黑白矩阵,求以每个点为右下角,能围出的周长最大的全白矩形的周长。\(n\leq2000\)。solution试图进行......
  • 焦点科技编程挑战赛2022题解
    比赛说明:比赛在四个学校开展,南理南航南农和矿大。题目查找文本差异要求origin和dest中分别包含1000w+条数据dest对数据进行了打乱操作,即origin和dest中相同数据行的......
  • CF1598F RBS 题解
    题意给\(n\)个串,求将这\(n\)个串以任意顺序接起来的最大的是合法括号序列的前缀数。分析\(n\)很小,考虑状压dp。有一个很典的转化是将(看成\(+1\),将)看成\(-......
  • CF 1743 题解
    比赛链接:https://codeforces.com/contest/1743题解:AB水题//bySkyRainWind#include<cstdio>#include<vector>#include<cstring>#include<iostream>#include......
  • week3题解
    1.寄包柜   看到题目最容易想到开二位数组但数据量过大,因此需要map#include<bits/stdc++.h>usingnamespacestd;map<int,map<int,int>>a;这里开了一个map......
  • el-date-picker 等 点击无反应不回显问题解决
    参考链接:https://blog.csdn.net/QQ2856639881/article/details/116918081?spm=1001.2101.3001.6661.1&depth_1-utm_relevant_index=1最近在做一个动态表单回显。数据嵌套......
  • vue项目中eslint报“Missing space before function parentheses”的问题解决
    原文链接:https://blog.csdn.net/u011523953/article/details/1067718681、问题原因:使用eslint时,严格模式下,报错Missingspacebeforefunctionparentheses(函数括号前缺少......
  • 【题解】CF1748D ConstructOR
    前言这道题十分诈骗,比赛的时候以为是根据二进制除法原理,解同余方程,然后考试时候就没做出来QAQ。这篇题解是构造解法,至于官方题解是啥我也不知道,看这官方题解的性质十分诡......