LightOJ 1074 - Extended Traffic 【SPFA】(经典)
<题目链接>
题目大意:
有n个城市,每一个城市有一个拥挤度$A_i$,从一个城市I到另一个城市J的时间为:$(A_v-A_u)^3$。问从第一个城市到达第$k$个城市所花的时间,如果不能到达,或者时间小于3输出?否则输出所花的时间。
解题分析:
很明显,此题路段的权值可能为负,所以我们就不能用Dijkstra算法求最短路了。需要注意的是,当点存在负环的时候,就要将负环所能够到达的所有点全部标记,从起点到这些点的最短路是不存在的(因为假设如果存在最短路,那么只要途中在负环上多走几遍,那么重新算得的时间一定会变少,所以不存在最短路)。所以,总的来说,对于本题,对那些负环能够到达的点,和从起点无法到达的点,和时间小于3的点,全部输出“?”,其他满足条件的直接输出最短时间就行。
#include <bits/stdc++.h>
using namespace std;
const int N = ,INF = 0x3f3f3f3f; struct Edge { int to,nxt,val; } edge[N * N]; int res, n;
int h[N];
bool vis[N]; //记录该点是否在队列内
bool cir[N]; //记录该点是否为负环上的点
int a[N], dist[N], cnt[N]; // cnt[]数组记录该数在队列中出现的次数 void dfs(int u) { //将该负环所能够达到的所有点全部标记
cir[u] = true;
for (int i = h[u]; i != -; i = edge[i].nxt) {
int v = edge[i].to;
if (!cir[v]) dfs(v);
}
}
void init() {
memset(h, -, sizeof(h));
res = ;
}
void add(int u, int v, int w) {
edge[res]=Edge{ v,h[u],w };h[u]=res++;
}
void SPFA(int st) {
memset(vis, false, sizeof(vis));
memset(cir, false, sizeof(cir));
memset(cnt, , sizeof(cnt));
for (int i = ; i <= n; i++) dist[i] = INF;
dist[st] = ;
queue<int> q;q.push(st);
cnt[st] = ;vis[st] = true;
while (!q.empty()) {
int u = q.front(); q.pop();
vis[u] = false; //当该点从队列中pop掉之后,就要清除vis标记
for (int i = h[u]; i != -; i = edge[i].nxt) {
int v = edge[i].to;
if (cir[v]) continue; //如果是负环上的点
if (dist[v] > dist[u] + edge[i].val) {
dist[v] = dist[u] + edge[i].val;
if (!vis[v]) { //如果该点不在队列中
vis[v] = true;
q.push(v);
cnt[v]++;
if (cnt[v] > n) dfs(v); //若存在负环,就用dfs将该负环能够达到的所有点标记
}
}
}
}
}
int main() {
int t; scanf("%d", &t);
int ncase = ;
while (t--) {
init();
scanf("%d", &n);
for (int i = ; i <= n; i++) scanf("%d", &a[i]);
int m; scanf("%d", &m);
while (m--) {
int u, v; scanf("%d %d", &u, &v);
add(u, v, (a[v] - a[u]) * (a[v] - a[u]) * (a[v] - a[u]));
}
SPFA();
printf("Case %d:\n", ++ncase);
scanf("%d", &m);
while (m--) {
int u;scanf("%d", &u);
if (cir[u] || dist[u] < || dist[u] ==INF) //如果询问的点能由负环达到、或者到起点的最小受益小于3、或者询问的点不可达
puts("?");
else printf("%d\n", dist[u]);
}
}
}
本题直接标记能够被负环上的点松弛>n次的点(包括负环上的点)也能过。
但是个人认为这种做法是不够严谨的,因为我的松弛是有终止条件的(因为没有必要,但是实际的问题时是能够在负环上一直转的),即,如果被松弛大于n次,就不再松弛,所以那些会被负环到达的点可能不会被松弛大于n次,比如它还能被别的路松弛,使得它到起点的距离非常短,这样负环上的点转了几圈之后才会小于它之前松弛的到起点的最短路,这样可能使得这个点进入队列的次数<n次(因为负环上的点我设置的是>n次自动终止)。
#include <bits/stdc++.h>
using namespace std;
const int N = , inf = 0x3f3f3f3f; struct Edge { int to,nxt,val; } edge[N * N]; bool vis[N], cir[N];
int n, h[N], res, a[N], dist[N], cnt[N]; //cnt[]数组记录该数在队列中出现的次数 void init() {
memset(h, -, sizeof(h));
res = ;
}
void add(int u, int v, int w) {
edge[res]=Edge{ v,h[u],w };h[u]=res++;
}
void SPFA(int st) {
memset(vis, false, sizeof(vis));
memset(cir, false, sizeof(cir));
memset(cnt, , sizeof(cnt));
for (int i = ; i <= n; i++) dist[i] = inf;
dist[st] = ;
queue<int> q;q.push(st);
cnt[st] = ;vis[st] = true;
while (!q.empty()) {
int u = q.front(); q.pop();
vis[u] = false;
for (int i = h[u]; i != -; i = edge[i].nxt) {
int v = edge[i].to;
if (cir[v]) continue;
if (dist[v] > dist[u] + edge[i].val) {
dist[v] = dist[u] + edge[i].val;
if (!vis[v]) {
vis[v] = true;
q.push(v);
cnt[v]++;
if(cnt[v]>n) cir[v]=true; //本题直接标记负环中的点以及能够被负环中的点松弛>n次的点也能过
}
}
}
}
}
int main() {
int t; scanf("%d", &t);
int ncase = ;
while (t--) {
init();
scanf("%d", &n);
for (int i = ; i <= n; i++) scanf("%d", &a[i]);
int m; scanf("%d", &m);
while (m--) {
int u, v; scanf("%d %d", &u, &v);
add(u, v, (a[v] - a[u]) * (a[v] - a[u]) * (a[v] - a[u]));
}
SPFA();
printf("Case %d:\n", ++ncase);
scanf("%d", &m);
while (m--) {
int u;scanf("%d", &u);
if (cir[u] || dist[u] < || dist[u] ==inf) puts("?");
else printf("%d\n", dist[u]);
}
}
}
类似于评论区里对最短距离的判断也能过(这与上面这个问题类似,但是也有一点区别)。
#include <bits/stdc++.h>
using namespace std;
const int N = , inf = 0x3f3f3f3f; struct Edge { int to,nxt,val; } edge[N * N]; bool vis[N], cir[N];
int n, h[N], res, a[N], dist[N], cnt[N]; void init() {
memset(h, -, sizeof(h));
res = ;
}
void add(int u, int v, int w) {
edge[res]=Edge{ v,h[u],w };h[u]=res++;
}
void SPFA(int st) {
memset(vis, false, sizeof(vis));
memset(cir, false, sizeof(cir));
memset(cnt, , sizeof(cnt));
for (int i = ; i <= n; i++) dist[i] = inf;
dist[st] = ;
queue<int> q;q.push(st);
cnt[st] = ;vis[st] = true;
while (!q.empty()) {
int u = q.front(); q.pop();
vis[u] = false;
for (int i = h[u]; i != -; i = edge[i].nxt) {
int v = edge[i].to;
if (cir[v]) continue;
if (dist[v] > dist[u] + edge[i].val) {
dist[v] = dist[u] + edge[i].val;
if (!vis[v]) {
vis[v] = true;
q.push(v);
cnt[v]++;
if(cnt[v]>n) cir[v]=true;
}
}
}
}
}
int main() {
int t; scanf("%d", &t);
int ncase = ;
while (t--) {
init();
scanf("%d", &n);
for (int i = ; i <= n; i++) scanf("%d", &a[i]);
int m; scanf("%d", &m);
while (m--) {
int u, v; scanf("%d %d", &u, &v);
add(u, v, (a[v] - a[u]) * (a[v] - a[u]) * (a[v] - a[u]));
}
SPFA();
printf("Case %d:\n", ++ncase);
scanf("%d", &m);
while (m--) {
int u;scanf("%d", &u);
if (dist[u] < || dist[u] == inf) puts("?");
else printf("%d\n", dist[u]);
}
}
}
LightOJ 1074 - Extended Traffic 【SPFA】(经典)的更多相关文章
- LightOj 1074 Extended Traffic (spfa+负权环)
题目链接: http://lightoj.com/volume_showproblem.php?problem=1074 题目大意: 有一个大城市有n个十字交叉口,有m条路,城市十分拥挤,因此每一个路 ...
- LightOJ 1074 Extended Traffic SPFA 消负环
分析:一看就是求最短路,然后用dij,果断错了一发,发现是3次方,有可能会出现负环 然后用spfa判负环,然后标记负环所有可达的点,被标记的点答案都是“?” #include<cstdio> ...
- LightOJ 1074 Extended Traffic(spfa+dfs标记负环上的点)
题目链接:https://cn.vjudge.net/contest/189021#problem/O 题目大意:有n个站点,每个站点都有一个busyness,从站点A到站点B的花费为(busynes ...
- LightOJ - 1074 Extended Traffic (SPFA+负环)
题意:N个点,分别有属于自己的N个busyness(简称b),两点间若有边,则边权为(ub-vb)^3.Q个查询,问从点1到该点的距离为多少. 分析:既然是差的三次方,那么可能有负边权的存在,自然有可 ...
- LightOJ 1074 - Extended Traffic (SPFA)
http://lightoj.com/volume_showproblem.php?problem=1074 1074 - Extended Traffic PDF (English) Stati ...
- LightOJ 1074 Extended Traffic (最短路spfa+标记负环点)
Extended Traffic 题目链接: http://acm.hust.edu.cn/vjudge/contest/122685#problem/O Description Dhaka city ...
- lightoj 1074 - Extended Traffic(spfa+负环判断)
题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1074 题意:有n个城市,每一个城市有一个拥挤度ai,从一个城市I到另一个城市J ...
- SPFA(负环) LightOJ 1074 Extended Traffic
题目传送门 题意:收过路费.如果最后的收费小于3或不能达到,输出'?'.否则输出到n点最小的过路费 分析:关键权值可为负,如果碰到负环是,小于3的约束条件不够,那么在得知有负环时,把这个环的点都标记下 ...
- (简单) LightOJ 1074 Extended Traffic,SPFA+负环。
Description Dhaka city is getting crowded and noisy day by day. Certain roads always remain blocked ...
随机推荐
- win 系统设置weblogic 进行定时自动重启并删除其日志和缓存文件,定时监控cpu是否达到100%并重启weblogic服务
一:如何在win系统设置 任务管理:请百度查询 win系统设置 任务管理 二:设置 webogic 重启并删除垃圾文件的bat脚本 sqlplus /nolog @C:\Users\Administr ...
- Confluence 6 配置索引语言
修改你 Confluence 的索引语言将有助于你提高搜索的准确性,如果你网站使用的主要语言是除了英语以外的其他语言. Confluence 可以支持下面语言的的内容索引: Arabic Brazil ...
- Confluence 6 配置服务器基础地址备注
使用不同 URL.如果你配置了不同的基础 URL 地址或者你站点的访问者使用了不同的 URL 地址来访问你的 Confluence 地址,你有很大概率可能会受到错误信息. 修改上下文地址.如果你修改了 ...
- Confluence 6 用户宏最佳实践
这个页面为你在创建用户宏的最佳实践中包含了一些小技巧和建议. 为你的宏添加一个简短的描述 我们鼓励你为你的宏在 模板(Template )添加一个备注的描述,可以参考下面的显示的内容: ## Macr ...
- 图片文字css小知识点
行内元素,图片和文字中间有缝隙,需要给父元素设置font-size:0: 图片和文字不对齐,给图片设置vertical-align:top 文字行高有缝隙 设置vertical-align:top
- python面试1-30题
1.一行代码实现1--100之和 利用sum()函数求和 2.如何在一个函数内部修改全局变量 利用global 修改全局变量 3.列出5个python标准库 os:提供了不少与操作系统相关联的函数 s ...
- hdu5758 思维,树形dp
/*可以推测从叶子结点传送到叶子节点才能使传送次数最少,如果是偶数个叶子结点,那么传送leaf/2次就是答案,如果是奇数个叶子结点,则还有单独一条链需要覆盖dp[u]表示覆盖完u为根的子树需要走的边数 ...
- python提取文件中的方法名称
#提取文件中的方法名称 # -*- coding:utf-8 -*- def Query_Method(filepath): file = open(filepath,'r',encoding= 'U ...
- springboot动态多数据源切换
application-test.properties #datasource -- mysql multiple.datasource.master.url=jdbc:mysql://localho ...
- Python3 zip() 函数
描述 zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的对象,这样做的好处是节约了不少的内存. 我们可以使用 list() 转换来输出列表. 如果 ...