• BZOJ 1877 晨跑 拆点费用流


    题目链接:

    https://www.lydsy.com/JudgeOnline/problem.php?id=1877

    题目大意:

    Elaxia最近迷恋上了空手道,他为自己设定了一套健身计划,比如俯卧撑、仰卧起坐等 等,不过到目前为止,他坚持下来的只有晨跑。 现在给出一张学校附近的地图,这张地图中包含N个十字路口和M条街道,Elaxia只能从 一个十字路口跑向另外一个十字路口,街道之间只在十字路口处相交。Elaxia每天从寝室出发 跑到学校,保证寝室编号为1,学校编号为N。 Elaxia的晨跑计划是按周期(包含若干天)进行的,由于他不喜欢走重复的路线,所以 在一个周期内,每天的晨跑路线都不会相交(在十字路口处),寝室和学校不算十字路 口。Elaxia耐力不太好,他希望在一个周期内跑的路程尽量短,但是又希望训练周期包含的天 数尽量长。 除了练空手道,Elaxia其他时间都花在了学习和找MM上面,所有他想请你帮忙为他设计 一套满足他要求的晨跑计划。output为两个数,第一个数为最长周期的天数,第二个数为满足最长天数的条件下最短的路程长度。

    思路:

    拆点费用流

      1 #include<bits/stdc++.h>
      2 #define IOS ios::sync_with_stdio(false);//不可再使用scanf printf
      3 #define Max(a, b) ((a) > (b) ? (a) : (b))//禁用于函数,会超时
      4 #define Min(a, b) ((a) < (b) ? (a) : (b))
      5 #define Mem(a) memset(a, 0, sizeof(a))
      6 #define Dis(x, y, x1, y1) ((x - x1) * (x - x1) + (y - y1) * (y - y1))
      7 #define MID(l, r) ((l) + ((r) - (l)) / 2)
      8 #define lson ((o)<<1)
      9 #define rson ((o)<<1|1)
     10 #define Accepted 0
     11 #pragma comment(linker, "/STACK:102400000,102400000")//栈外挂
     12 using namespace std;
     13 inline int read()
     14 {
     15     int x=0,f=1;char ch=getchar();
     16     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
     17     while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
     18     return x*f;
     19 }
     20 typedef long long ll;
     21 const int maxn = 1000 + 10;
     22 const int MOD = 1000000007;//const引用更快,宏定义也更快
     23 const int INF = 1e9 + 7;
     24 const double eps = 1e-6;
     25 
     26 struct edge
     27 {
     28     int u, v, c, f, cost;
     29     edge(int u, int v, int c, int f, int cost):u(u), v(v), c(c), f(f), cost(cost){}
     30 };
     31 vector<edge>e;
     32 vector<int>G[maxn];
     33 int a[maxn];//找增广路每个点的水流量
     34 int p[maxn];//每次找增广路反向记录路径
     35 int d[maxn];//SPFA算法的最短路
     36 int inq[maxn];//SPFA算法是否在队列中
     37 int n, m;
     38 void addedge(int u, int v, int c, int cost)
     39 {
     40     e.push_back(edge(u, v, c, 0, cost));
     41     e.push_back(edge(v, u, 0, 0, -cost));
     42     int m = e.size();
     43     G[u].push_back(m - 2);
     44     G[v].push_back(m - 1);
     45 }
     46 bool bellman(int s, int t, int& flow, long long & cost)
     47 {
     48     for(int i = 0; i <= t + 1; i++)d[i] = INF;//Bellman算法的初始化
     49     memset(inq, 0, sizeof(inq));
     50     d[s] = 0;inq[s] = 1;//源点s的距离设为0,标记入队
     51     p[s] = 0;a[s] = INF;//源点流量为INF(和之前的最大流算法是一样的)
     52 
     53     queue<int>q;//Bellman算法和增广路算法同步进行,沿着最短路拓展增广路,得出的解一定是最小费用最大流
     54     q.push(s);
     55     while(!q.empty())
     56     {
     57         int u = q.front();
     58         q.pop();
     59         inq[u] = 0;//入队列标记删除
     60         for(int i = 0; i < G[u].size(); i++)
     61         {
     62             edge & now = e[G[u][i]];
     63             int v = now.v;
     64             if(now.c > now.f && d[v] > d[u] + now.cost)
     65                 //now.c > now.f表示这条路还未流满(和最大流一样)
     66                 //d[v] > d[u] + e.cost Bellman 算法中边的松弛
     67             {
     68                 d[v] = d[u] + now.cost;//Bellman 算法边的松弛
     69                 p[v] = G[u][i];//反向记录边的编号
     70                 a[v] = min(a[u], now.c - now.f);//到达v点的水量取决于边剩余的容量和u点的水量
     71                 if(!inq[v]){q.push(v);inq[v] = 1;}//Bellman 算法入队
     72             }
     73         }
     74     }
     75     if(d[t] == INF)return false;//找不到增广路
     76     flow += a[t];//最大流的值,此函数引用flow这个值,最后可以直接求出flow
     77     cost += (long long)d[t] * (long long)a[t];//距离乘上到达汇点的流量就是费用
     78     for(int u = t; u != s; u = e[p[u]].u)//逆向存边
     79     {
     80         e[p[u]].f += a[t];//正向边加上流量
     81         e[p[u] ^ 1].f -= a[t];//反向边减去流量 (和增广路算法一样)
     82     }
     83     return true;
     84 }
     85 int MincostMaxflow(int s, int t, long long & cost)
     86 {
     87     cost = 0;
     88     int flow = 0;
     89     while(bellman(s, t, flow, cost));//由于Bellman函数用的是引用,所以只要一直调用就可以求出flow和cost
     90     return flow;//返回最大流,cost引用可以直接返回最小费用
     91 }
     92 int main()
     93 {
     94     int n, m;
     95     scanf("%d%d", &n, &m);
     96     int s = 1, t = 2 * n;
     97     for(int i = 2; i < n; i++)
     98         addedge(i, i + n, 1, 0);
     99 
    100     addedge(s, s + n, INF, 0);
    101     addedge(n, t, INF, 0);
    102     while(m--)
    103     {
    104         int u, v, w;
    105         scanf("%d%d%d", &u, &v, &w);
    106         addedge(u + n, v, 1, w);
    107     }
    108     ll cost;
    109     printf("%d", MincostMaxflow(s, t, cost));
    110     printf(" %lld
    ", cost);
    111     return Accepted;
    112 }
  • 相关阅读:
    Android开发——Activity启动模式详解
    Spring核心技术(十一)——基于Java的容器配置(一)
    【数学】控制论
    【Mongo】聚合函数
    【Deeplearning】blog
    【Python】添加注册表信息脚本
    【数据库】备份与恢复
    【MongoDB】数组长度查询
    【Mysql】修改最大连接数
    【Python】多线程2
  • 原文地址:https://www.cnblogs.com/fzl194/p/9696292.html
Copyright © 2020-2023  润新知