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\)个不同位置,要求每个位置至少有一个元素,求分配方 ...
随机推荐
- 关于javascript的slice方法
slice方法在javascript中既可以在Array对象的原型下也可以是在String对象的原型下;其中w3c上面说的slice方法的第一个参数是必须的;这里的说法有误; slice的参数可以是0 ...
- mongodb用mongoose取到的对象不能增加属性
先定义了一个article的schema var mongoose = require('mongoose'); var Schema = mongoose.Schema; exports.schem ...
- hdu 1092 A+B for Input-Output Practice (IV)
A+B for Input-Output Practice (IV) Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/327 ...
- 【Android自动化打包】03. APK的数字签名
1. 什么是数字签名? 数字签名就是为你的程序打上一种标记,来作为你自己的标识,当别人看到签名的时候会知道它是与你相关的 2. 为什么要数字签名? 最简单直接的回答: 系统要求的. ...
- 1.1、Mybatis一级缓存测试
package me.gacl.test; import me.gacl.domain.User; import me.gacl.util.MyBatisUtil; import org.apache ...
- asp生成静态HTML(动态读取)
这样的代码多用于我们没有实现设计生成静态的功能,但又想临时将一些动态页面生成静态的,直接获取动态内容并保存为静态的 复制代码代码如下: <!--#include file="admin ...
- .net 并发
Nhibernate并发参考 http://www.cnblogs.com/lyj/archive/2008/10/21/1316269.html EF并发参考 http://www.cnblogs. ...
- 如何覆盖aar的资源
1.首先理解一下aar的构造 classes.jar ----代码 res---资源文件 2.替换 查看res里面的资源文件,这个资源文件事实上都是跟安卓的资源文件夹是一样的.你只需要理解xml和里面 ...
- Android中Tomcat的简单配置和使用
因为学Android已经有一段时间了,但是在学校,服务器方面是个短板啊,没有专门的服务器拿给我们学生练手,所以只有自己找办法了.当然,Tomcat就是不二的选择了. 在网上看了看资料,还是觉得自己记录 ...
- SQLserver数据库基础
1·控制数据库的服务 运行 cmd 在控制面板输入 net start MSSQLserver (启动数据库服务) 在控制面板输入 net stop MSSQLserver ( ...