http://tyvj.cn/Problem_Show.aspx?id=1467

这题我并不是看题解a的。但是确实从题解得到了启发。

一开始我就想到一个正解,设d[i][0]表示i开始走过奇数个点的最短路,d[i][1]表示i走过偶数个点的最短路,那么转移很简单

d[v][1]=min(d[v][1], d[u][0]+w(u, v)) 当(u, v)是奇数才能走的边

d[v][0]=min(d[v][0], d[u][1]+w(u, v)) 当(u, v)是偶数才能走的边

然后每一个人都跑一次spfa。。。。。答案为min(d[n][0], d[n][1]),在跑spfa初始化为d[s][1]=0,因为一开始算偶数个

显然tle。。

原因是每一次都跑一次spfa,那么时间无法承受。

看了题解说是逆向建图从n跑spfa,我一想,对啊!

但是有个问题,答案是多少呢。。

答案是d[u][1]没错,也就是说u算偶数个的时候。

但是转移要改。

因为从n跑,所以初始化为d[n][0]=d[n][1]=0,这就会造成奇变偶,偶变奇!

不信你看,当(u, v)这条边是奇边时,且v==n,我们之前的转移转移到的是d[u][1]!但是答案显然不是d[u][1],而是d[u][0],因为这条边是奇边,转移到的是u的偶,但是从u的角度来看,u应该要是奇

如果按原来的转移,那么答案是d[u][0]

我们来转换一下转移

d[v][1]=min(d[v][1], d[u][0]+w(u, v)) 当(u, v)是偶数才能走的边

d[v][0]=min(d[v][0], d[u][1]+w(u, v)) 当(u, v)是奇数才能走的边

那么答案就是d[u][1]了

至于题解说的拆点,我觉得没必要。。。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
#define rep(i, n) for(int i=0; i<(n); ++i)
#define for1(i,a,n) for(int i=(a);i<=(n);++i)
#define for2(i,a,n) for(int i=(a);i<(n);++i)
#define for3(i,a,n) for(int i=(a);i>=(n);--i)
#define for4(i,a,n) for(int i=(a);i>(n);--i)
#define CC(i,a) memset(i,a,sizeof(i))
#define read(a) a=getint()
#define print(a) printf("%d", a)
#define dbg(x) cout << #x << " = " << x << endl
#define printarr(a, n, m) rep(aaa, n) { rep(bbb, m) cout << a[aaa][bbb]; cout << endl; }
inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }
inline const int max(const int &a, const int &b) { return a>b?a:b; }
inline const int min(const int &a, const int &b) { return a<b?a:b; } using namespace std; const int N=10005, M=100005, oo=~0u>>1;
int d[N][2], ihead[N], cnt, vis[N], q[N], tail, front, n, m;
struct ED { int to, next, w, jo; } e[M];
inline void add(const int &u, const int &v, const int &w) {
e[++cnt].next=ihead[u]; ihead[u]=cnt; e[cnt].to=v; e[cnt].w=w;
}
inline const void spfa(const int &s) {
CC(d, 0x3f); CC(vis, 0);
d[s][1]=d[s][0]=tail=front=0; vis[s]=1; q[tail++]=s;
int u, v, w;
while(front!=tail) {
u=q[front++]; if(front==N) front=0; vis[u]=0;
for(int i=ihead[u]; i; i=e[i].next) {
v=e[i].to; w=e[i].w;
if(e[i].jo==1) {
if(d[v][0]>d[u][1]+w) {
d[v][0]=d[u][1]+w;
if(!vis[v]) { vis[v]=1; q[tail++]=v; if(tail==N) tail=0; }
}
}
else if(e[i].jo==2) {
if(d[v][1]>d[u][0]+w) {
d[v][1]=d[u][0]+w;
if(!vis[v]) { vis[v]=1; q[tail++]=v; if(tail==N) tail=0; }
}
}
else {
if(d[v][1]>d[u][0]+w) {
d[v][1]=d[u][0]+w;
if(!vis[v]) { vis[v]=1; q[tail++]=v; if(tail==N) tail=0; }
}
if(d[v][0]>d[u][1]+w) {
d[v][0]=d[u][1]+w;
if(!vis[v]) { vis[v]=1; q[tail++]=v; if(tail==N) tail=0; }
}
}
}
}
}
int main() {
read(n); read(m);
int u, v, w, ans=oo;
char name[30], nm[30];
while(m--) {
read(u); read(v); read(w);
add(v, u, w);
}
read(u); while(u--) e[getint()].jo+=1;
read(u); while(u--) e[getint()].jo+=2;
spfa(n);
read(u); while(u--) {
read(v); scanf("%s", name);
if(ans>d[v][1]) {
ans=d[v][1];
strcpy(nm, name);
}
}
printf("%s\n%d\n", nm, ans);
return 0;
}

背景 Background

Candy住在一个被划分为n个区域的神奇小镇中,其中Candy的家在编号为n的区域,Candy生日这天,大家都急急忙忙赶去Candy家庆祝Candy的生日。

描述 Description

Candy共有t个朋友住在不同的区域。小镇有m条道路,小镇的神奇之处在于其中的p1条道路只会在你走过区域的的个数为奇数时候开启,p2道路只会 在你走过区域的个数为偶数的时候开启,剩下的道路一直都会开启。并且,所有的道路只能够单向通过。飘飘乎居士希望知道在所有的好朋友中,谁离Candy最 近?。

输入格式 InputFormat

第一行:两个正整数n m,表示共n个区域,m条道路
                    接下来m行,每行三个正整数u v s表示u到v的单向道路,路程为s,其中第i条道路的编号为i。
                    接着一个整数p1以及p1个正整数odd[i],表示编号为odd[i]的道路只会在走过奇数个区域时开启。
                    接着一个整数p2以及p2个正整数even[i],表示编号为even[i]的道路只会在走过偶数个区域时开启。
                    接下来一个正整数 t
                    紧接着t行,每行一个正整数h以及一个不超过10个字符长度的字符串na(且均有小写字母组成),表示在h区域居住着名字为na的人。

输出格式 OutputFormat

第一行,即距离candy家最近的人的名字,数据保证有且只有一个人为最后的答案。      
第二行,该人到candy家的距离。
        如果存在多解,则输入名字中字典序较小的一人。

样例输入 SampleInput [复制数据]

4 5
1 2 2
3 4 2
2 4 4
1 3 1
2 3 1
1 4 
1 2
2
2 violethill
1 pink

样例输出 SampleOutput [复制数据]

violethill
4

数据范围和注释 Hint

pink尽管从1->3->4距离更近,但因为1->2的这条道路只有在走过奇数个区域时才开启,而pink此时走过的区域为偶数个 (0个)(我们规定,出发点不算走第一个区域),所以pink只好沿1—>2—>3—>4,距离为5;
Violethill尽
管沿2—>3—>4距离为3,但因为3—>4这条道路只有在走过偶数个区域时才开启,当violethill从2到3时,只走了奇数个
(1个)区域,道路不会开启。所以,violethill只好沿2—>4这条道路行走,距离为4,所以violethill比pink更快到
candy家中,并且距离为4。
对于30%的数据 0<n<=100
对于100%的数据0<n<=10000   0<m<=100000
对于所有数据保证两区域间的距离<=100000
数据保证运算即结果在maxlongint以内
数据保证输入的正确性,即至少有一个人可以到达candy家中,并且一个区域最多只有一人,不会出现相同名字的人。
友情提示:可能出现有些道路既在odd中出现,也在even中出现。并且odd或者even中的数都可能出现重复数字。

【TYVJ】1467 - 通向聚会的道路(spfa+特殊的技巧)的更多相关文章

  1. tyvj1467 通向聚会的道路

    背景   Candy住在一个被划分为n个区域的神奇小镇中,其中Candy的家在编号为n的区域,Candy生日这天,大家都急急忙忙赶去Candy家庆祝Candy的生日. 描述   Candy共有t个朋友 ...

  2. luogu P1462 通往奥格瑞玛的道路--spfa+二分答案

    P1462 通往奥格瑞玛的道路 题目背景 在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量 有一天他醒来后发现自己居然到了联盟的主城暴风城 在被众多联盟的士兵攻击后,他决定逃回自己的家乡 ...

  3. 洛谷P1462 通往奥格瑞玛的道路(SPFA+二分答案)

    题目背景 在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量 有一天他醒来后发现自己居然到了联盟的主城暴风城 在被众多联盟的士兵攻击后,他决定逃回自己的家乡奥格瑞玛 题目描述 在艾泽拉斯, ...

  4. [HNOI/AHOI2018]道路

    Description: W 国的交通呈一棵树的形状.W 国一共有\(n - 1\)个城市和\(n\)个乡村,其中城市从\(1\)到\(n - 1\) 编号,乡村从\(1\)到\(n\)编号,且\(1 ...

  5. 【HNOI 2018】道路

    Problem Description \(W\) 国的交通呈一棵树的形状.\(W\) 国一共有\(n - 1\)个城市和\(n\)个乡村,其中城市从\(1\)到\(n - 1\) 编号,乡村从\(1 ...

  6. [HNOI2018]道路 --- 树形DP

    [HNOI2018]道路 题目描述: W 国的交通呈一棵树的形状.W 国一共有 \(n-1\) 个城市和 \(n\) 个乡村, 其中城市从 \(1\) 到 \(n-1\) 编号,乡村从 \(1\) 到 ...

  7. loj #2510. 「AHOI / HNOI2018」道路

    #2510. 「AHOI / HNOI2018」道路 题目描述 W 国的交通呈一棵树的形状.W 国一共有 n−1 个城市和 nnn 个乡村,其中城市从 111 到 n−1 编号,乡村从 111 到 n ...

  8. [HNOI2018]道路(DP)

    题目描述 W 国的交通呈一棵树的形状.W 国一共有n−1n - 1n−1 个城市和nnn 个乡村,其中城市从111 到n−1n - 1n−1 编号,乡村从111 到nnn 编号,且111 号城市是首都 ...

  9. bzoj 1576: [Usaco2009 Jan]安全路经Travel【spfa+树链剖分+线段树】

    这几天写USACO水题脑子锈住了--上来就贪心,一交就WA 事实上这个是一个叫最短路树的东西,因为能保证只有一条最短路,所以所有最短路合起来是一棵以1为根的树,并且在这棵树上,每个点被精灵占据的路是它 ...

随机推荐

  1. apache ab压力测试报错(apr_socket_recv: Connection reset by peer (104))

    apache ab压力测试报错(apr_socket_recv: Connection reset by peer (104))   今天用apache 自带的ab工具测试,当并发量达到1000多的时 ...

  2. C 结构体小结

    看了三天结构体,是时候总结一下了. 关于结构体的声明: struct Student { ]; char sex; int age; ]; }; /*然后定义一个Student 类型的 student ...

  3. linux增加自定义path和manpath

    linux安装软件到自定义路径时,新安装的命令需要带上路径才可以执行,不能像系统自带命令那样可以直接使用. 这个时候可以通过修改环境变量PATH和MANPATH,来实现像系统命令一样使用新安装的命令并 ...

  4. JavaScript 使用 sort() 方法从数值上对数组进行排序

    使用 sort() 方法从数值上对数组进行排序. <html> <body> <script type="text/javascript"> f ...

  5. AngularJS服务中serivce,factory,provider的区别

    Angular服务是一个由服务工厂创建的单例对象.这些服务工厂是由 service provider 依次创建的.而service providers是构造函数.它们必须包含一个$get属性用于在实例 ...

  6. ios 动态测定字符串frame : boundingRectWithSize函数

    用NSString中的一个方法,第一个参数是text形成的frame的最大的宽度和高度, 其中的options比较关键 CGSize labelSize = [text boundingRectWit ...

  7. Cocos2d 学习资料推荐

    总算找到了一本介绍cocos2d的好书,注意,不是cocos2d-x!这本书叫 <cocos2d 权威指南> 定价99元,淘宝60多元,详细介绍了cocos2d的各个方面!不过你需要有oc ...

  8. 12.python笔记之mysqldb模块

    一.使用python调用模块操作MYsql 2.x版本使用mysqldb模块 3.x版本使用pymysql模块 1.数据库常用操作: 使用Navicat for MySql软件来操作 show dat ...

  9. Greedy:Stripes(POJ 1826)

    新生物 题目大意:给你一堆数,两两结合,答案为2*sqrt(x1*x2),问组合成一个数时,最小的量? 超级无敌大水题,排序或者用堆都可以,反正就是优先组合大的,让根号一直把大数开根降低整体的大小 # ...

  10. NEFU 2016省赛演练一 I题 (模拟题)

    这题没名字 Problem:I Time Limit:2000ms Memory Limit:65535K Description Now give you an interger m and a s ...