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\)个不同位置,要求每个位置至少有一个元素,求分配方 ...
随机推荐
- 为ubuntu只带的network-manager添加latp/ipsec VPN
sudo apt-add-repository ppa:seriy-pr/network-manager-l2tp sudo apt-get update sudo apt-get install n ...
- JavaGUI实现点名系统
有一个名字数组,根据线程知识是框中的数据依次修改 package Week1008; import java.awt.Font; import java.awt.event.ActionEvent; ...
- ASP.NET MVC中的统一化自定义异常处理
当ASP.NET MVC程序出现了异常,怎么处理更加规范? 1. 最简单的方法是设置<customErrors/>节点 <customErrors>节点用于定义一些自定义错误信 ...
- 利用CodeSmith生成抽象工厂步骤
其实CodeSmith挺好的,帮我们主动生成不少代码,并且代码质量不错,下面就来介绍一下利用CodeSmith生成抽象工厂步骤 打开codesmith模板的buildall 注意path的设置,因为后 ...
- 异步请求---Get
前端 <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> &l ...
- Apache 流媒体 拖动模块编译
Windows使用apxs独立编译 Apache 模块 http://blog.sina.com.cn/s/blog_43b83d340100mdhl.html 安装 apxs 1.解压apxs.zi ...
- windows2003可用gt630显卡驱动
http://file2.mydrivers.com/display/301.42-desktop-winxp-32-international-whql.exe 驱动精灵自动下载的不好用,这个版本可 ...
- Java实战之03Spring-04Spring的数据库访问
四.Spring的数据库访问 1.DAO模式 /** * 抽取的一个类 * @author zhy * */ public class JdbcDaoSupport { private QueryRu ...
- Java实战之02Hibernate-06处理并发
十三.处理并发 1.事务的隔离级别 不考虑隔离级别出现的问题: 脏读:一个线程中的事务读到了另外一个线程中未提交的数据. 不可重复读:一个线程中的事务读到了另外一个线程中提交的update(更新)的数 ...
- [leetcode] 400. Nth Digit
https://leetcode.com/contest/5/problems/nth-digit/ 刚开始看不懂题意,后来才理解是这个序列连起来的,看一下第几位是几.然后就是数,1位数几个,2位数几 ...