BZOJ 3955 Surely You Congest 解题报告
首先,我们可以求出源为 $1$ 号点的最短路图以及各个点到 $1$ 号点的最短路。
然后我们考虑那些距离不同的点,是一定不会发生拥堵现象的。
然后我们就只需要考虑那些距离相同的点,就相当于做一个最大流嘛。
假设考虑与 $1$ 号节点距离为 $d$ 的点,那怎么连边,怎么设置源和汇呢?
- 源为 $1$ 号节点,新开一个 $n+1$ 号节点作为汇。
- 对于所有满足 $dist(1, x) + w(x,y) = dist(1, y)$ 的 $x,y$ 建一条 $x\rightarrow y$ 的边,容量为 $1$。
- 如果某个点 $x$ 与 $1$ 号节点距离恰好为 $d$,建一条 $x\rightarrow T$ 的边,容量为这个点上车辆的数目。
然后把所有距离下的最大流加起来,就是答案了。
复杂度看起来有点高,不过加点优化应该还是能跑过去的。
我加了一个优化:如果与 $1$ 号节点距离为 $d$ 的车辆只有 $1$ 辆,那么最大流就是 $1$,就不用去跑网络流了。
感觉效果还不错。
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
#define C 2000 + 5
#define N 50000 + 5
#define M 400000 + 5
#define SIZE 10000000 + 5
#define INF 0x7fffffff int n, m, c, S, T, tot, _tot, ans;
int A[C];
int Head[N], _Head[N], Inq[N];
int Dis[N], _Dis[N];
int E[M][];
int q[SIZE]; struct Edge
{
int next, node, flow, w;
}h[M], _h[M]; inline void addedge(int u, int v, int fl, int w)
{
h[++ tot].next = Head[u], Head[u] = tot;
h[tot].node = v, h[tot].flow = fl, h[tot].w = w;
h[++ tot].next = Head[v], Head[v] = tot;
h[tot].node = u, h[tot].flow = , h[tot].w = w;
} inline bool SPFA(int S)
{
for (int i = S; i <= T; i ++)
Dis[i] = INF, Inq[i] = ;
int l = , r = ;
Dis[S] = , q[] = S, Inq[S] = ;
while (l <= r)
{
int z = q[l ++];
Inq[z] = ;
for (int i = Head[z]; i; i = h[i].next)
{
int d = h[i].node, p = h[i].flow, w = h[i].w;
if (!p) continue ;
if (Dis[d] > Dis[z] + w)
{
Dis[d] = Dis[z] + w;
if (!Inq[d])
{
q[++ r] = d;
Inq[d] = r;
}
}
if (Inq[d] && Dis[d] < Dis[q[l]])
{
int u = Inq[d], v = q[l];
q[l] = d, q[u] = v;
Inq[d] = l, Inq[v] = u;
}
}
}
return Dis[T] != INF;
} inline void Copy()
{
_tot = tot;
for (int i = S; i <= T; i ++)
_Head[i] = Head[i], _Dis[i] = Dis[i];
for (int i = ; i <= tot; i ++)
_h[i] = h[i];
} inline void Restore()
{
tot = _tot;
for (int i = S; i <= T; i ++)
Head[i] = _Head[i];
for (int i = ; i <= _tot; i ++)
h[i] = _h[i];
} inline bool cmp(int u, int v)
{
return Dis[u] < Dis[v];
} inline int dinic(int z, int inflow)
{
if (z == T || !inflow) return inflow;
int ret = inflow, flow;
for (int i = Head[z]; i; i = h[i].next)
{
int d = h[i].node, p = h[i].flow;
if (Dis[d] != Dis[z] + ) continue ;
flow = dinic(d, min(ret, p));
ret -= flow;
h[i].flow -= flow, h[i ^ ].flow += flow;
if (!ret) return inflow;
}
if (ret == inflow) Dis[z] = -;
return inflow - ret;
} int main()
{
#ifndef ONLINE_JUDGE
freopen("3955.in", "r", stdin);
freopen("3955.out", "w", stdout);
#endif scanf("%d%d%d", &n, &m, &c);
S = , T = n + ;
for (int i = ; i <= m; i ++)
{
int u, v, w;
scanf("%d%d%d", &u ,&v, &w);
E[i][] = u, E[i][] = v, E[i][] = w;
addedge(u, v, , w);
addedge(v, u, , w);
}
SPFA();
for (int i = ; i <= c; i ++)
scanf("%d", A + i);
sort(A + , A + c + , cmp);
tot = ;
memset(Head, , sizeof(Head));
for (int i = ; i <= m; i ++)
{
if (Dis[E[i][]] + E[i][] == Dis[E[i][]])
addedge(E[i][], E[i][], , );
if (Dis[E[i][]] + E[i][] == Dis[E[i][]])
addedge(E[i][], E[i][], , );
}
Copy();
int l = , r;
for (; l <= c; l = r + )
{
for (r = l; r < c && _Dis[A[r + ]] == _Dis[A[l]]; r ++) ;
if (r == l) ans ++;
else
{
Restore();
for (int i = l; i <= r; i ++)
addedge(A[i], T, , );
while (SPFA(S))
ans += dinic(S, INF);
}
}
printf("%d\n", ans); #ifndef ONLINE_JUDGE
fclose(stdin);
fclose(stdout);
#endif
return ;
}
3955_Gromah
BZOJ 3955 Surely You Congest 解题报告的更多相关文章
- bzoj 1565 [NOI2009]植物大战僵尸 解题报告
1565: [NOI2009]植物大战僵尸 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 2161 Solved: 1000[Submit][Stat ...
- BZOJ 4029 [HEOI 4029] 定价 解题报告
这个题好像也是贪心的感觉.. 我们枚举 $1,5,10,50,100,\dots$ ,找出在 $[l, r]$ 内能整除它们的最小的数. 然后找到其中在荒谬值最小的情况下数值最小的那个数, 就做完了. ...
- BZOJ 3998 [TJOI 2015] 弦论 解题报告
这是一道后缀自动机经典题目. 对于 $t=0$ 的情况:每个节点都代表一个子串,所以我们给每个节点的 $Size$ 都记为 $1$, 对于 $t=1$ 的情况:我们只给 $last$ 节点的 $Siz ...
- BZOJ 3997 [TJOI 2015 组合数学] 解题报告
这个题我脑洞了一个结论: 首先,我们定义满足以下条件的路径为“从右上到左下的路径”: 对于路径上任何不相同的两个点 $(x_1, y_1)$,$(x_2, y_2)$,都有: $x_1\neq x_2 ...
- BZOJ 3996 [TJOI 2015] 线性代数 解题报告
首先,我们可以得到: $$D = \sum_{i=1}^{n}\sum_{j=1}^{n}a_i\times a_j\times b_{i,j} - \sum_{i=1}^{n}a_i\times c ...
- BZOJ 3990 [SDOI 2015] 排序 解题报告
这个题哎呀...细节超级多... 首先,我猜了一个结论.如果有一种排序方案是可行的,假设这个方案是 $S$ . 那么我们把 $S$ 给任意重新排列之后,也必然可以构造出一组合法方案来. 于是我们就可以 ...
- BZOJ 3929 Circle of digits 解题报告
首先,我们可以得到最高位的位数为:\(\lfloor\frac{n+k-1}{n}\rfloor\),记作 \(E\). 然后给这 \(n\) 个长为 \(E\) 的数字排序,后缀数组 \(O((n+ ...
- BZOJ 4145 [AMPPZ2014] The Prices 解题报告
感觉也是一个小清新题.. 我们考虑设立状态 $Dp[i][s]$ 表示考虑了前 $i$ 个商店后,购买状态为 $s$ 的最小花费. 转移的话就枚举每个商店 $i$,首先令: $$Dp[i][s] = ...
- BZOJ 4710 [Jsoi2011]分特产 解题报告
4710 [Jsoi2011]分特产 题意 给定\(n\)个集合,每个集合有相同的\(a_i\)个元素,不同的集合的元素不同.将所有的元素分给\(m\)个不同位置,要求每个位置至少有一个元素,求分配方 ...
随机推荐
- [转]c#.NET和VB.NET语法的比较
本文转自:http://www.cnblogs.com/lify0407/archive/2007/08/01/838589.html c#.NET和VB.NET语法的比较 VB.NET C# C ...
- UVA 11021 - Tribles(概率)
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=481&page=s ...
- css-实现元素垂直居中对齐
css-实现元素/元素内容,垂直居中对齐 一.单行内容的垂直居中(line-height:行高方法) 只考虑单行是最简单的,无论是否给容器固定高度,只要给容器设置 line-height 和 heig ...
- 【译文】NginScript – 为什么我们要实现自己的JS引擎?
在上周的nginx.conf 2015用户大会上,我们发布了全新的JavaScript引擎nginscript的预览版.历史上,JavaScript语言已经应用在许多方面,首先是作为客户端脚本,然后又 ...
- length prototype 函数function的属性,以及构造函数
前言:学到一些JavaScript高级的知识,在这里记下,方便以后的查找 1.length代表函数定义的形参的个数,挺简单的 例如:function Pen(price,cname) { . ...
- VBA实现随意输入组合码,查询唯一标识码
记录背景: 需要在excel中查询出组合码,对应的唯一标识码. 举例 组合码:4+5+6+9+1*2 标识码:A1 界面随意输入组合码:1*2+4+5+6+9 输出标识码:A1 VBA实现: P ...
- 用法简单的图片和视频播放的框架Demo
最近在恶补自己不足的基础知识,偶然在一个QQ群里看到作为同行业的大神们在开源自己的代码.并且在炫耀说让我们找Bug,于是出于好奇就看了下,点开了一个关于图片和视频播放的Demo.也就是接下来我要说的这 ...
- Easyui-Combobox多选下拉框
因为工作需要,引入combobox多选下拉框,并且获取选择的值并以","分开. 效果如下: 代码如下: <html> <head> <title> ...
- SQL SERVER 级联删除
有三个表: Company Address Contact 在Address和Contact中建立外键,外键id为company的id, 那么就不能任意删除Company.但假如在外键约束中把级联删除 ...
- 用PL0语言求Fibonacci数列前m个中偶数位的数
程序说明:求Fibonacci数列前m个中偶数位的数: 这是编译原理作业,本打算写 求Fibonacci数列前m个数:写了半天,不会写,就放弃了: 程序代码如下: var n1,n2,m,i; pro ...