传送门


发现它的本质是求一个费用最小的路径覆盖

最小路径覆盖是网络流23题中的一个比较典型的模型

所以考虑相似的建边

因为每一个点要恰好经过一次,是一个有上下界的网络流,故拆点,星球\(i\)拆成\(A_i,B_i\)两个点,\(S->B_i , A_i -> T\),原图中的边\((i,j)\)变为\(B_i -> A_j\),费用不变。

接下来我们需要考虑费用的设置

首先\(S->B_i\)的边的费用显然是通过空间跳跃到达这个点需要的时间\(a_i\)。

但有一个问题:在上面以最小路径覆盖问题为模板建立出的模型中,点\(B_i\)的出度流对应的实际上只是一条路径上的一条边\((i,j)\)而并非一整条路径。这意味着一条路径上除了终点以外所有点的\(a_i\)在费用流中都被加了进来。

考虑怎么减掉这个额外出现的空间跳跃费用。不难想到将\(A_i -> T\)边的费用设置为\(-a_i\)。这样非起点非终点的所有点\(a_i\)的贡献就会变为\(0\)。但是在这种情况下终点\(a_i\)的贡献却又是\(-a_i\)。

发现问题在于\(S->B_i\)边没有流。那么加上\(B_i -> T\)、流量1费用0的边,这样\(S->B_i\)就会有\(1\)的流,终点的空间跳跃时间就会变为\(0\),就能保证路径上所有点空间跳跃时间是正确的了。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<cctype>
#include<algorithm>
#include<cstring>
#include<iomanip>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<vector>
#include<cmath>
#define INF 0x3f3f3f3f
//This code is written by Itst
using namespace std;

inline int read(){
    int a = 0;
    char c = getchar();
    bool f = 0;
    while(!isdigit(c) && c != EOF){
        if(c == '-')
            f = 1;
        c = getchar();
    }
    if(c == EOF)
        exit(0);
    while(isdigit(c)){
        a = (a << 3) + (a << 1) + (c ^ '0');
        c = getchar();
    }
    return f ? -a : a;
}

const int MAXN = 2e4 + 3 , MAXM = 1e5 + 3;
struct Edge{
    int end , upEd , f , c;
}Ed[MAXM];
int head[MAXN] , cur[MAXN] , dep[MAXN] , dis[MAXN] , pre[MAXN] , flo[MAXN];
int N , M , S , T , cntEd = 1;
bool vis[MAXN];
queue < int > q;

inline void addEd(int a , int b , int c , int d = 0){
    Ed[++cntEd].end = b;
    Ed[cntEd].upEd = head[a];
    Ed[cntEd].f = c;
    Ed[cntEd].c = d;
    head[a] = cntEd;
}

inline bool bfs(){
    while(!q.empty())
        q.pop();
    q.push(S);
    memset(dep , 0 , sizeof(dep));
    dep[S] = 1;
    while(!q.empty()){
        int t = q.front();
        q.pop();
        for(int i = head[t] ; i ; i = Ed[i].upEd)
            if(Ed[i].f && !dep[Ed[i].end]){
                dep[Ed[i].end] = dep[t] + 1;
                if(Ed[i].end == T){
                    memcpy(cur , head , sizeof(head));
                    return 1;
                }
                q.push(Ed[i].end);
            }
    }
    return 0;
}

inline int dfs(int x , int mF){
    if(x == T)
        return mF;
    int sum = 0;
    for(int &i = cur[x] ; i ; i = Ed[i].upEd)
        if(Ed[i].f && dep[Ed[i].end] == dep[x] + 1){
            int t = dfs(Ed[i].end , min(mF - sum , Ed[i].f));
            if(t){
                Ed[i].f -= t;
                Ed[i ^ 1].f += t;
                sum += t;
                if(sum == mF)
                    break;
            }
        }
    return sum;
}

int Dinic(){
    int ans = 0;
    while(bfs())
        ans += dfs(S , INF);
    return ans;
}

inline bool SPFA(){
    memset(dis , 0x3f , sizeof(dis));
    dis[S] = 0;
    while(!q.empty())
        q.pop();
    q.push(S);
    flo[S] = INF;
    while(!q.empty()){
        int t = q.front();
        q.pop();
        vis[t] = 0;
        for(int i = head[t] ; i ; i = Ed[i].upEd)
            if(Ed[i].f && dis[Ed[i].end] > dis[t] + Ed[i].c){
                dis[Ed[i].end] = dis[t] + Ed[i].c;
                flo[Ed[i].end] = min(Ed[i].f , flo[t]);
                pre[Ed[i].end] = i;
                if(!vis[Ed[i].end]){
                    vis[Ed[i].end] = 1;
                    q.push(Ed[i].end);
                }
            }
    }
    return dis[T] != dis[T + 1];
}

int EK(){
    int ans = 0;
    while(SPFA()){
        int cur = T , sum = 0;
        while(cur != S){
            sum += Ed[pre[cur]].c;
            Ed[pre[cur]].f -= flo[T];
            Ed[pre[cur] ^ 1].f += flo[T];
            cur = Ed[pre[cur] ^ 1].end;
        }
        ans += sum * flo[T];
    }
    return ans;
}

bool in[MAXN];
int nxt[MAXN];

int main(){
#ifndef ONLINE_JUDGE
    freopen("in" , "r" , stdin);
    //freopen("out" , "w" , stdout);
#endif
    N = read();
    M = read();
    T = 2 * N + 2;
    for(int i = 1 ; i <= N ; ++i){
        int a = read();
        addEd(S , i + N , 1 , a);
        addEd(i + N , S , 0 , -a);
        addEd(i , T , 1 , -a);
        addEd(T , i , 0 , a);
        addEd(i + N , T - 1 , 1);
        addEd(T - 1 , i + N , 0);
    }
    addEd(T - 1 , T , INF);
    addEd(T , T - 1 , 0);
    for(int i = 1 ; i <= M ; ++i){
        int a = read() , b = read() , c = read();
        if(a > b)
            swap(a , b);
        addEd(a + N , b , 1 , c);
        addEd(b , a + N , 0 , -c);
    }
    cout << EK();
    return 0;
}

Luogu2469 SDOI2010 星际竞速 费用流的更多相关文章

  1. BZOJ 1927: [Sdoi2010]星际竞速 费用流

    1927: [Sdoi2010]星际竞速 Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/pr ...

  2. BZOJ 1927: [Sdoi2010]星际竞速(费用流)

    传送门 解题思路 仿照最小路径覆盖问题,用费用流解决此题.最小路径覆盖问题是拆点连边后用\(n-\)最大匹配,这里的话也是将每个点拆点,源点向入点连流量为\(1\),费用为\(0\)的边,向出点连流量 ...

  3. [SDOI2010]星际竞速——费用流

    类似于最短路的网络流,而且还要保证每个点经过一次,拆点就比较方便了. 连边怎么连?要保证最大流是n(每个点经过一次)还要能从直接跳转 将每个点拆点.源点向每个点的入点连一条容量为1费用为0的边.源点向 ...

  4. BZOJ 1927 星际竞速(费用流)

    考虑费用流,题目要求走n个点都走完且恰好一次,显然流量的限制为n. 建立源点s和汇点t,并把每个星球拆成两个点i和i',分别表示已到达该点和经过该点. 对于能力爆发,建边(s,i',1,w). 对应高 ...

  5. bzoj 1927 [Sdoi2010]星际竞速(最小费用最大流)

    1927: [Sdoi2010]星际竞速 Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 1576  Solved: 954[Submit][Statu ...

  6. BZOJ 1927: [Sdoi2010]星际竞速(最小费用最大流)

    拆点,费用流... ----------------------------------------------------------------------------- #include< ...

  7. BZOJ 1927: [Sdoi2010]星际竞速 [上下界费用流]

    1927: [Sdoi2010]星际竞速 题意:一个带权DAG,每个点恰好经过一次,每个点有曲速移动到他的代价,求最小花费 不动脑子直接上上下界费用流过了... s到点连边边权为曲速的代价,一个曲速移 ...

  8. BZOJ1927 [Sdoi2010]星际竞速 【费用流】

    1927: [Sdoi2010]星际竞速 Time Limit: 20 Sec  Memory Limit: 259 MB Submit: 2582  Solved: 1601 [Submit][St ...

  9. P2469 [SDOI2010]星际竞速(费用流)

    P2469 [SDOI2010]星际竞速 最小路径覆盖问题 每个星球必须恰好去一次,而每次高速航行都是从一个星球到另一个星球. 那么高速航行的起点可以保证被去过 高速航行和空间跳跃可以是互相独立的 将 ...

随机推荐

  1. AWT初步— 事件处理模型

    之前学习的内容只能形成一个用户界面,而用户不能对其有实际的操作,也就是说用户界面没有任何功能.要能够让图形界面接收用户的操作,就必须给各个组件加上事件处理机制.在事件处理的过程中,主要涉及三类对象: ...

  2. loadrunner 脚本开发-定义全局变量

    脚本开发-定义全局变量 by:授客 QQ:1033553122 如果参数是全局的,在脚本中的任何一个Action中都可以使用,变量一般是局部的,如果跨Action调用会出现未声明的错误. 打开Scri ...

  3. JavaWeb:Listener和Filter

    本文内容: Listener Filter 首发日期:2018-07-15 Listener 监听器Listener负责监听事件的发生.我们能在事件发生后执行一些自定义的操作,这就是监听器的意义. 监 ...

  4. JAVA学习笔记:注释、变量的声明和定义、

    本文内容: 注释 变量的声明和定义 成员变量和局部变量 首发时间:2018-03-16 15:59 注释: 单行注释:// 多行注释:/* - */ 变量: 变量是内存中的一个存储区域,变量的定义就是 ...

  5. BigDecimal遇到的问题,大伙也说说

    一:相除精度丢失的问题 BigDecimal的api除法相对加减乘要实现的复杂多了,只介绍常用的我遇到的问题: 问题:两数相除,如果9/3=3整除没问题,但是10/3=0.33333333...... ...

  6. 【第四篇】SAP ABAP7.5x新语法之CREATE DATA&INTERFACE

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文地址:SAP ABAP7.5x系列之CREATE DA ...

  7. 怎样让引用类库的类在HelpPage上显示Description

        最近在做 web api 开发的时候遇到这样的问题,即 HelpPage 里只能显示 api 控制器上的注释,对于那些引用了外部类库的类(比如POST提交需要用到的类),就无法显示它们的备注, ...

  8. apache 访问权限出错,apache selinux 权限问题, (13) Permission Denied

    今天在使用 httpd 做文件服务器的时候,发现 png 图像没有打开,但是原本www/html 文件夹内部的文件就可以打开.后来猜测是selinux 的问题,之前一直想写一篇关于selinux 的博 ...

  9. windows下编写shell脚本执行错误

    在 windows 下,换行符是 \r\n,在linux下,换行符是 \n.如果你在IDEA里写sh脚本,可以手动设置脚本的换行符为 \n,如果你用notepad++写脚本,可以显示所有字符,以便明确 ...

  10. January 30th, 2018 Week 05th Tuesday

    The things you own end up owning you. 你占有的东西终将会占有你. When we are longing for something, we would be w ...