香港记者
2017-08-21 19:00
127 查看
Description
众所周知,香港记者跑得比谁都快,这其中其实是有秘诀的。首先他们会跑最短路,但是最短路会有很多条,而且其他记者也知道要跑最短路,香港记者还统计出了每座城市带黑框眼镜的人数,如果一个记者跑路的时候城市带黑框眼镜人数的序列字典序比另一个记者大,那么这个记者就会被不可描述的力量续走时间,导致他跑得没字典序小的记者快。
长者日续万秒日理万机,想请你告诉他香港记者经过的总路程和城市带黑框眼镜人数的序列,方便他找到香港记者,传授他们一些人生经验。
方便起见,设起点为 1 终点为 n。
由于续命的多样性不可描述的力量,各个城市带黑框眼镜的人数各不相同。
Input
输入文件名为 journalist.in。第一行,两个整数 n; m 表示有 n 个城市,城市之间有 m 条有向边。
第二行, n 个数,表示每个城市带黑框眼镜的人数 bi:
接下来 m 行,每行 3 个非负整数 ui; vi; wi 表示一条有向边的起点,终点,路程。
Output
输出文件名为 journalist.out。第一行,一个非负整数表示香港记者经过的总路程。
第二行,若干个非负整数表示香港记者经过的城市带黑框眼镜人数的序列。
Sample Input
8 91 2 3 4 5 6 7 8
1 2 2
2 3 3
3 8 3
1 4 3
4 5 2
5 8 1
1 6 1
6 7 2
7 8 3
Sample Output
61 4 5 8
Hint
对于前 30% 的数据, 2 ≤ n ≤ 2 × 103, 1 ≤ m ≤ 4 × 103。对于前 60% 的数据,保证数据随机。
对于另外 30% 的数据,保证所有起点到终点的简单路径(没有环的路径)长度相同。
对于 100% 的数据, 2 ≤ n ≤ 2 × 105, 1 ≤ m ≤ 4 × 105, 1 ≤ w ≤ 1 × 109,存在至少一条从
起点到终点的最短路。
题解
解法一:我们可以先求出最短路。
然后搜索求出路径。
对于u−>v,如果
dist[v]==dist[u]+w(u,v)
就继续拓展。
我们可以加边的时候先将后继节点按点权排序,这样贪心保证搜出的第一条策略就是满足条件的。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<queue> using namespace std; typedef long long lol; template <typename T> void read(T &x) { x=0;char c=getchar(); for(;!isdigit(c);c=getchar()); for(;isdigit(c);c=getchar())x=x*10+c-'0'; } int n,m,s[200005]; struct Edge { int from,to;lol dis; }map[400005]; int size=0,head[200005]; struct node { int next,to; lol dis; }edge[400005]; void putin(int from,int to,lol dis) { size++; edge[size].next=head[from]; edge[size].to=to; edge[size].dis=dis; head[from]=size; } bool cmp(const Edge a,const Edge b) { if(a.from!=b.from)return a.from<b.from; if(a.to!=b.to)return s[a.to]>s[b.to]; else return a.dis<b.dis; } lol dist[200005]; int vis[200005],pre[200005]; void SPFA(int r) { memset(dist,127/3,sizeof(dist)); queue<int>mem; mem.push(r); vis[r]=1; dist[r]=0; while(!mem.empty()) { int x=mem.front();mem.pop(); vis[x]=0; for(int i=head[x];i!=-1;i=edge[i].next) { int y=edge[i].to; if(dist[y]>dist[x]+edge[i].dis) { dist[y]=dist[x]+edge[i].dis; if(!vis[y]) { mem.push(y); vis[y]=1; } } } } return; } bool ok; void dfs(int r) { if(r==n)ok=1; if(ok)return; int i; for(i=head[r];i!=-1;i=edge[i].next) { int y=edge[i].to; if(dist[y]==dist[r]+edge[i].dis) { pre[y]=r; dfs(y); } } } int ans[200005],cnt; void write(int r) { while(r!=1) { ans[++cnt]=s[r]; r=pre[r]; } ans[++cnt]=s[r]; for(int i=cnt;i>=2;i--)printf("%d ",ans[i]); printf("%d",ans[1]); return; } int main() { freopen("journalist.in","r",stdin); freopen("journalist.out","w",stdout); int i,j; read(n);read(m); memset(head,-1,sizeof(head)); for(i=1;i<=n;i++)read(s[i]); for(i=1;i<=m;i++) { read(map[i].from); read(map[i].to); read(map[i].dis); } sort(map+1,map+m+1,cmp); for(i=1;i<=m;i++)putin(map[i].from,map[i].to,map[i].dis); SPFA(1); printf("%lld\n",dist ); dfs(1); write(n); return 0; }
解法二:
我们可以存储逆边,逆向做一次SPFA。
pre[u]表示u的后继节点
松弛的时候如果
dist[v]>dist[u]+w(u,v)
就
dist[v]=dist[u]+w(u,v);
如果
dist[v]==dist[u]+w(u,v)
此时若pre[v]的点权大于u的点权,我们将
pre[v]=u;
由于字典序高位越小越好,满足最优子结构,贪心是可行的。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #include<queue> using namespace std; typedef long long lol; template <typename T> void read(T &x) { x=0;char c=getchar(); for(;!isdigit(c);c=getchar()); for(;isdigit(c);c=getchar())x=x*10+c-'0'; } int n,m,size=0,head[200005],s[200005]; struct node { int next,to; lol dis; }edge[400005]; void putin(int from,int to,lol dis) { size++; edge[size].next=head[from]; edge[size].to=to; edge[size].dis=dis; head[from]=size; } lol dist[200005]; int vis[200005],pre[200005]; void SPFA(int r) { memset(dist,127/3,sizeof(dist)); memset(pre,127/3,sizeof(pre)); queue<int>mem; mem.push(r); vis[r]=1; dist[r]=0; while(!mem.empty()) { int x=mem.front();mem.pop(); vis[x]=0; for(int i=head[x];i!=-1;i=edge[i].next) { int y=edge[i].to; if(dist[y]==dist[x]+edge[i].dis&&s[pre[y]]>s[x])pre[y]=x; if(dist[y]>dist[x]+edge[i].dis) { dist[y]=dist[x]+edge[i].dis; pre[y]=x; if(!vis[y]) { mem.push(y); vis[y]=1; } } } } return; } void write(int r) { while(r!=n) { printf("%d ",s[r]); r=pre[r]; } printf("%d",s[r]); return; } int main() { freopen("journalist.in","r",stdin); freopen("journalist.out","w",stdout); int i,j; memset(head,-1,sizeof(head)); read(n);read(m); for(i=1;i<=n;i++) read(s[i]); for(i=1;i<=m;i++) { int from,to,dis; read(from);read(to);read(dis); putin(to,from,dis); } SPFA(n); printf("%lld\n",dist[1]); write(1); return 0; }
相关文章推荐
- 香港记者
- JZOJ5279. 【NOIP提高组模拟A组8.15】香港记者
- 【jzoj5279】【NOIP提高组模拟A组8.15】【香港记者】
- JZOJ.5279【NOIP2017模拟8.15】香港记者
- [测试题]香港记者
- JZOJ 5279 香港记者
- 香港影评会选出电影史上十大华语片
- 中国香港放水,中国也无缘世界杯
- 香港本地电视台简介
- 香港十大气质男明星
- 香港电信大重组 任正非李泽楷打响香港之役
- 一个清华学生在香港留学受到的心灵震憾[转]
- 刘翔回击日挑衅记者:我代表亚洲但不包括日本!
- 鲁迅先生就ERP实施问题答记者问
- Google Maps卫星地图新增印度、新加坡、香港交通地图
- 香港回归10年纪念《始终有你》
- 香港回归十周年,纪念下.
- 一个清华学生在香港读研受到的心灵震撼
- 昨日,重庆北火车站,新生和家长有序登上开往学校的直通车。记者杨新宇摄
- 香港