2019HDU多校第一场 6582 Path 【最短路+最大流最小割】

一、题目

  Path

二、分析

  首先肯定要求最短路,然后如何确定所有的最短路其实有多种方法。

  1 根据最短路,那么最短路上的边肯定是可以满足$dist[from] + e.cost = dist[to]$。所以可以求一遍后根据这个公式再向网络图中的加边即可。

  2 可以从源点和汇点分别求最短路,然后根据每条边肯定满足$dist1[e.from] + e.cost + dist2[e.to] = dij$,再加边就行了。

  确定最短路后,由于是求最小割,直接跑$Dinic$求出最大流就可以了。

三、AC代码

  1 #include <bits/stdc++.h>
  2
  3 using namespace std;
  4 #define Min(a, b) ((a)>(b)?(b):(a))
  5 #define P pair<ll, int>
  6 #define ll long long
  7 const ll INF = __LONG_LONG_MAX__;
  8 const int maxn = 2e4 + 13;
  9 const int maxm = 2e4 + 13;
 10 int N, M;
 11
 12 struct edge
 13 {
 14     int to, cost;
 15 };
 16 struct edge2
 17 {
 18     ll to, cap, rev;
 19 };
 20 ll dist1[maxn], dist2[maxn];
 21 vector<edge> G1[maxn], G2[maxn];    //G1正向图,G2反向图
 22 vector<edge2> G[maxn << 2];
 23
 24 void addedge(ll from, ll to, ll cap)
 25 {
 26     G[from].push_back((edge2){to, cap, (ll)G[to].size()});
 27     G[to].push_back((edge2){from, 0, (ll)G[from].size()-1});
 28 }
 29
 30 void dijkstra()
 31 {
 32     priority_queue<P, vector<P>, greater<P>> pque;
 33     pque.push(P(0, 1));
 34     fill(dist1, dist1 + N + 2, INF);
 35     dist1[1] = 0;
 36     while(!pque.empty())
 37     {
 38         P q = pque.top();
 39         pque.pop();
 40         int v = q.second;
 41         if(dist1[v] < q.first)
 42             continue;
 43         for(int i = 0; i < G1[v].size(); i++)
 44         {
 45             edge e = G1[v][i];
 46             if(dist1[v] + e.cost < dist1[e.to])
 47             {
 48                 dist1[e.to] = dist1[v] + e.cost;
 49                 pque.push(P(dist1[e.to], e.to));
 50             }
 51         }
 52     }
 53
 54     // pque.push(P(0, N));
 55     // fill(dist2, dist2 + N + 2, INF);
 56     // dist2[N] = 0;
 57     // while(!pque.empty())
 58     // {
 59     //     P q = pque.top();
 60     //     pque.pop();
 61     //     int v = q.second;
 62     //     if(dist2[v] < q.first)
 63     //         continue;
 64     //     for(int i = 0; i < G2[v].size(); i++)
 65     //     {
 66     //         edge e = G2[v][i];
 67     //         if(dist2[v] + e.cost < dist2[e.to])
 68     //         {
 69     //             dist2[e.to] = dist2[v] + e.cost;
 70     //             pque.push(P(dist2[e.to], e.to));
 71     //         }
 72     //     }
 73     // }
 74 }
 75
 76 void getGraph()
 77 {
 78     dijkstra();
 79     ll Dij = dist1[N];
 80     for(int i = 1; i <= N; i++)
 81     {
 82         for(int j = 0; j < G1[i].size(); j++)
 83         {
 84             edge e = G1[i][j];
 85             if(dist1[e.to] - dist1[i] == e.cost)
 86             {
 87                 addedge((ll)i, (ll)e.to, (ll)e.cost);
 88             }
 89         }
 90     }
 91     // for(int i = 1; i <= N; i++)
 92     // {
 93     //     for(int j = 0; j < G1[i].size(); j++)
 94     //     {
 95     //         edge e = G1[i][j];
 96     //         if(dist1[i] + e.cost + dist2[e.to] == Dij)
 97     //         {
 98     //             addedge((ll)i, (ll)e.to, (ll)e.cost);
 99     //         }
100     //     }
101     // }
102 }
103
104 ll level[maxn], iter[maxn<<2];
105
106 void BFS(ll s)
107 {
108     memset(level, -1, sizeof(level));
109     queue<int> que;
110     que.push(s);
111     level[s] = 0;
112     while(!que.empty())
113     {
114         int v = que.front();
115         que.pop();
116         for(int i = 0; i < G[v].size(); i++)
117         {
118             edge2 e = G[v][i];
119             if(e.cap > 0 && level[e.to] < 0)
120             {
121                 level[e.to] = level[v] + 1;
122                 que.push(e.to);
123             }
124         }
125     }
126 }
127
128 ll DFS(ll v, ll t, ll f)
129 {
130     if(v == t)
131         return f;
132     for(ll &i = iter[v]; i < G[v].size(); i++)
133     {
134         edge2 &e = G[v][i];
135         if(e.cap > 0 && level[v] < level[e.to])
136         {
137             ll d = DFS(e.to, t, min(f, e.cap));
138             if(d > 0)
139             {
140                 e.cap -= d;
141                 G[e.to][e.rev].cap += d;
142                 return d;
143             }
144         }
145     }
146     return 0;
147 }
148
149 ll Dinic(ll s, ll t)
150 {
151     ll flow = 0;
152     while(1)
153     {
154         BFS(s);
155         if(level[t] < 0)
156             return flow;
157         memset(iter, 0, sizeof(iter));
158         ll f = DFS(s, t, INF);
159         while(f > 0)
160         {
161             flow += f;
162             f = DFS(s, t, INF);
163         }
164     }
165 }
166
167 int main()
168 {
169     //freopen("input.txt", "r", stdin);
170     int T;
171     scanf("%d", &T);
172     while(T--)
173     {
174         int from, to, cost;
175         scanf("%d%d", &N, &M);
176         for(int i = 0; i <= N; i++)
177         {
178             G[i].clear();
179             G1[i].clear();
180             G2[i].clear();
181         }
182         for(int i = 0; i < M; i++)
183         {
184             scanf("%d%d%d", &from, &to, &cost);
185             G1[from].push_back( (edge){to, cost});
186             G2[to].push_back( (edge){from, cost});
187         }
188         getGraph();
189         printf("%lld\n", Dinic(1, N));
190     }
191
192 }

原文地址:https://www.cnblogs.com/dybala21/p/11324554.html

时间: 2024-08-30 13:21:21

2019HDU多校第一场 6582 Path 【最短路+最大流最小割】的相关文章

HDU 5294 多校第一场1007题 最短路+最小割

Tricks Device Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1285    Accepted Submission(s): 302 Problem Description Innocent Wu follows Dumb Zhang into a ancient tomb. Innocent Wu’s at the ent

[2019杭电多校第一场][hdu6582]Path

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6582 题意:删掉边使得1到n的最短路改变,删掉边的代价为该边的边权.求最小代价. 比赛时一片浆糊,赛后听到dinic瞬间思维通透XD 大致做法就是先跑一边最短路,然后再保留所有满足dis[i]+w==dis[j]的边,在这些边上跑最小割(dinic). 代码写的异常丑陋,见谅QAQ 1 #include<iostream> 2 #include<cstdio> 3 #include&l

[2019HDU多校第一场][HDU 6590][M. Code]

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6590 题目大意(来自队友):二维平面上有\(n\)个点,每个点要么是黑色要么是白色,问能否找到一条直线将平面分割成黑白两部分 题解:分别对每种颜色的点求凸包,判断是否相交即可. (有模板真好) 1 #include<bits/stdc++.h> 2 //#include<cstdio> 3 //#include<cmath> 4 //#include<algorith

2019HDU多校第一场 BLANK DP

题意:有四种数字,现在有若干个限制条件:每个区间中不同的数字种类必须是多少种,问合法的方案数. 思路: 定义 dp[i][j][k][t] 代表填完前 t 个位置后,{0,1,2,3} 这 4 个数字最后一次出现的位置, 排序后为 i,j,k,t(i < j < k < t) 的方案数目,则按照第 t+1 位的数字的四种选择,可以得 到四种转移. 对于限制可以按照限制区间的右端点分类,求出 dp[i][j][k][t] 后,找到所有以 t 为区间 右端点的限制条件,如果当前状态不满足所有

2014多校第一场A题 || HDU 4861 Couple doubi

题目链接 题意 : 有K个球,给你一个数P,可以求出K个值,(i=1,2,...,k) : 1^i+2^i+...+(p-1)^i (mod p).然后女朋友先取,再xp取,都希望赢,如果女朋友能赢输出YES,否则输出NO 思路 :这个题,在纸上算算差不多就出来结果了,因为要赢,所以一开始必定拿大的,根据规律可以发现最后的那个取余结果不是0就是某个数,所以就看那个数有奇数个还是偶数个即可. 官方题解: 1 #include <stdio.h> 2 #include <string.h&g

2014多校第一场 I 题 || HDU 4869 Turn the pokers(费马小定理+快速幂模)

题目链接 题意 : m张牌,可以翻n次,每次翻xi张牌,问最后能得到多少种形态. 思路 :0定义为反面,1定义为正面,(一开始都是反), 对于每次翻牌操作,我们定义两个边界lb,rb,代表每次中1最少时最少的个数,rb代表1最多时的个数.一张牌翻两次和两张牌翻一次 得到的奇偶性相同,所以结果中lb和最多的rb的奇偶性相同.如果找到了lb和rb,那么,介于这两个数之间且与这两个数奇偶性相同的数均可取到,然后在这个区间内求组合数相加(若lb=3,rb=7,则3,5,7这些情况都能取到,也就是说最后的

暑期多校 第一场

A: 描述: 代码: 1 #include <iostream> 2 #include <stdio.h> 3 #include <math.h> 4 #include <string.h> 5 using namespace std; 6 7 int k,p; 8 int a[104]; 9 //void solve(){ 10 // int ans=0; 11 // for(int i=1;i<=k;i++){ 12 // ans=0; 13 //

2014多校第一场D题 || HDU 4864 Task (贪心)

题目链接 题意 : 用N台机器,M个任务,每台机器都有一个最大工作时间和等级,每个任务有一个需要工作时间和一个等级.如果机器完成一个任务要求是:机器的工作时间要大于等于任务的时间,机器的等级要大于等于任务的等级.一台机器只能完成一个任务,一个任务只能被一台机器完成.每个机器完成一个任务公司能够获得500*xi+2*yi (此处xy都是指被完成的任务的).输出所有机器能完成的最多任务数,和最大盈利. 思路 :贪心,自己做的时候想了各种排序都不对,没有考虑到500*xi+2*yi 这个公式的重要性.

2014多校第一场J题 || HDU 4870 Rating(DP || 高斯消元)

题目链接 题意 :小女孩注册了两个比赛的帐号,初始分值都为0,每做一次比赛如果排名在前两百名,rating涨50,否则降100,告诉你她每次比赛在前两百名的概率p,如果她每次做题都用两个账号中分数低的那个去做,问她最终有一个账号达到1000分需要做的比赛的次数的期望值. 思路 :可以直接用公式推出来用DP做,也可以列出210个方程组用高斯消元去做. (1)DP1:离散化.因为50,100,1000都是50的倍数,所以就看作1,2,20.这样做起来比较方便. 定义dp[i]为从 i 分数到达i+1