香港记者

Posted kakakakakaka

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了香港记者相关的知识,希望对你有一定的参考价值。

Description

众所周知,香港记者跑得比谁都快,这其中其实是有秘诀的。
首先他们会跑最短路,但是最短路会有很多条,而且其他记者也知道要跑最短路,香港记者还统计出了每座城市带黑框眼镜的人数,如果一个记者跑路的时候城市带黑框眼镜人数的序列字典序比另一个记者大,那么这个记者就会被不可描述的力量续走时间,导致他跑得没字典序小的记者快。
长者日续万秒日理万机,想请你告诉他香港记者经过的总路程和城市带黑框眼镜人数的序列,方便他找到香港记者,传授他们一些人生经验。
方便起见,设起点为 终点为 n
由于续命的多样性不可描述的力量,各个城市带黑框眼镜的人数各不相同。

Input

输入文件名为 journalist.in
第一行,两个整数 n; m 表示有 个城市,城市之间有 条有向边。
第二行, 个数,表示每个城市带黑框眼镜的人数 bi
接下来 行,每行 个非负整数 ui; vi; w表示一条有向边的起点,终点,路程。 

Output

输出文件名为 journalist.out
第一行,一个非负整数表示香港记者经过的总路程。
第二行,若干个非负整数表示香港记者经过的城市带黑框眼镜人数的序列。

Sample Input

8 9
1 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

6
1 4 5 8

Hint

对于前 30的数据, ≤ ≤ × 103, ≤ ≤ × 103
对于前 60的数据,保证数据随机。
对于另外 30的数据,保证所有起点到终点的简单路径(没有环的路径)长度相同。
对于 100的数据, ≤ ≤ × 105, ≤ ≤ × 105, ≤ ≤ × 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[n]);
    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;
}

 

以上是关于香港记者的主要内容,如果未能解决你的问题,请参考以下文章

BFS最短路径还原+字典序UVA 1599 Ideal Path 和 UPC 4431香港记者

腾讯云要在全球搞事情!已率先在香港开始

腾讯云开放香港第二个数据中心

Robin8 Blockchain Summit脑冻记者前线直击

钻石模式:那是如何(去)规范化的?

如果美国祭出SWIFT这个大招,我们怎么办?