【TYVJ】1467 - 通向聚会的道路(spfa+特殊的技巧)

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 51 2 23 4 22 4 41 3 12 3 11 4 1 222 violethill1 pink

样例输出 SampleOutput [复制数据]

violethill4

数据范围和注释 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中的数都可能出现重复数字。

时间: 2024-10-11 16:59:45

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

tyvj:P1467 通向聚会的道路

背景 Candy住在一个被划分为n个区域的神奇小镇中,其中Candy的家在编号为n的区域,Candy生日这天,大家都急急忙忙赶去Candy家庆祝Candy的生日. 描述 Candy共有t个朋友住在不同的区域.小镇有m条道路,小镇的神奇之处在于其中的p1条道路只会在你走过区域的的个数为奇数时候开启,p2道路只会在你走过区域的个数为偶数的时候开启,剩下的道路一直都会开启.并且,所有的道路只能够单向通过.飘飘乎居士希望知道在所有的好朋友中,谁离Candy最近?. 输入格式 第一行:两个正整数n m,表

tyvj1467 通向聚会的道路

背景 Candy住在一个被划分为n个区域的神奇小镇中,其中Candy的家在编号为n的区域,Candy生日这天,大家都急急忙忙赶去Candy家庆祝Candy的生日. 描述 Candy共有t个朋友住在不同的区域.小镇有m条道路,小镇的神奇之处在于其中的p1条道路只会在你走过区域的的个数为奇数时候开启,p2道路只会在你走过区域的个数为偶数的时候开启,剩下的道路一直都会开启.并且,所有的道路只能够单向通过.飘飘乎居士希望知道在所有的好朋友中,谁离Candy最近?. 输入格式 第一行:两个正整数n m,表

通向膨胀的道路(关于 “separation of concerns” (SoC)的原则)

When it comes to CSS, I believe that the sacred principle of “separation of concerns” (SoC) has lead us to accept bloat, obsolescence, redundancy, poor caching and more. Now, I’m convinced that the only way to improve how we author style sheets is by

小结:最短路

概要: 最短路是个神奇的东西,通过三角不等式,我们可以拓展出很多最短路的延伸.而求最短路的算法一般我用三种,dijkstra.spfa.floyd,第一个用于点少边多的,第一个用于点多边少的,第三个是多源最短路. 应用: 差分约束系统.一般约束条件.最短路等. 技巧及注意: 差分约束:根据三角不等式d(v)<=d(u)+w(u, v),我们通过移项,还可以得到d(v)+w(u, v)<=d(u),而这样就足以解决一些不等式约束集了,即差分约束(在一些情况下,可以考虑最长路的三角不等式).例如[

大神刷题表

9月27日 后缀数组:[wikioi3160]最长公共子串 dp:NOIP2001统计单词个数 后缀自动机:[spoj1812]Longest Common Substring II [wikioi3160]最长公共子串 [spoj7258]Lexicographical Substring Search 扫描线+set:[poj2932]Coneology 扫描线+set+树上删边游戏:[FJOI2013]圆形游戏 结论:[bzoj3706][FJ2014集训]反色刷 最小环:[poj1734

新概念英语第三册51-60课(转)

Lesson 51  Predicting the future 预测未来 1.预测世界的未来Predicting the future是众所周知的困难.is notoriously difficult. 众所周知预测未来很困难.Predicting the future is notoriously difficult. 众所周知预测未来很困难. 2.谁过去能够曾经想象过, Who could have imagined, 在20世纪70年代中叶,in the mid 1970s, 例如,fo

Java NIO:NIO概述

在上一篇博文中讲述了几种IO模型,现在我们开始进入Java NIO编程主题.NIO是Java 4里面提供的新的API,目的是用来解决传统IO的问题.本文下面分别从Java NIO的几个基础概念介绍起. 以下是本文的目录大纲: 一.NIO中的几个基础概念 二.Channel 三.Buffer 四.Selector 若有不正之处,请多多谅解并欢迎批评指正. 一.NIO中的几个基础概念 在NIO中有几个比较关键的概念:Channel(通道),Buffer(缓冲区),Selector(选择器). 首先从

孩子,我首先希望你自始至终都是一个理想主义者

孩子,我首先希望你自始至终都是一个理想主义者. 作者:张梅    孩子,我首先希望你自始至终都是一个理想主义者. 你可以是农民,可以是工程师,可以是演员,可以是流浪汉, 但你必须是个理想主义者. 当你童年,我们讲英雄的故事给你听, 并不是要你一定成为英雄,而是希望你具有纯正的品格: 当你年少,我们让你接触诗歌,绘画,音乐, 是为了让你的心灵填满高尚的情趣, 这些高尚的情趣会支撑你的一生, 使你在最严酷的冬天也不会忘记玫瑰的芳香. 孩子,不要为自己 的外形担忧. 理想纯洁你的气质, 而最美的女人也

固化型思维与成长型思维

最近读完一本书,<看见成长的自己>,这本书让我审视了自己长久以来所接受的思维观点,并给了我战胜心魔的力量,让我以后能专注把事情做更好,而不是因自己心里障碍做不了事.我把书里精彩的句子摘抄如下. 1. 在僵固思维模式里,这些品质代表的只是你手上的一把牌,而你总是试图说服自己和他人这是一把同花顺,却在内心深处担心这只是一对10.然而,在另外一种思维模式中,这把牌(不论是什么)仅仅是你走向成功的起点. 2. "不去冒险,就不会失败","如果你一开始没有成功,也许你就没有