【NOIP模拟】军队调遣

题面

OI 国有 N 座城市,每座城市有唯一的 1 到 N 的标号。其中 1 号城市为首都。 OI 国的交通 十分发达,共有 M 条有向道路,已知通过第 i 条道路所需时间为 ti。  林大帝的统治使 OI 国走向了繁荣。  不幸的是,各地都仍旧有一些不老实的人在捣蛋。林大帝实在是不能忍了。为了加强治安, 保障国土的完整,林大帝派人在每座城市(除了首都本身)招募军队去剿匪。匪徒都是些乌合 之众,没过一会儿就被林大帝的精锐之师打得落花流水、心服口服。  为了庆祝剿匪胜利,各地的军队都必须尽快到首都集合。然而,行军是会产生劳累值的,且 军队在剿匪之后十分疲惫,所以他们会优先选择劳累值最小的路径。如果有多个劳累值最小的 路径,他们会在其中选择用时最少的路径。  当军队经过一条 u 到 v 的道路时,如果 v 能够到达 u,士兵们就会有绕圈的感觉,故产生 1 单位的劳累值;否则,士兵们会有说有笑地前进,不会产生劳累值。一条路径的劳累值为路径 上所有边的劳累值之和,一条路径的用时为路径上所有边的用时之和,如有边重复经过需累计。 你需要对每座城市计算其军队将选择的路径的劳累值及用时,或指出无法到达首都。

输出共 N − 1 行,第 i 行描述 i + 1 号城市的军队选择的路径情况。如果该城市的军队不能 到达首都,输出 -1;否则输出两个整数依次表示劳累值和用时。

分析

通过计算用时可以感知出是一个最短路问题,但是多了劳累值的问题,稍微复杂一点

但是要使u能到v并且v能到u,对于有向图来说,很明显是在一个环里,所以我们只需要将强连通分量染色,再给边标上第二层边权,如果两节点为同一个强连通分量里,则边权标为1,否则标为0。

之后通过最短路算法,同时计算时间和劳累值的最小,但是按照劳累值优先。

注意建图需要反向建!

#include<bits/stdc++.h>
using namespace std;
#define N 100100
#define INF 0X7fffffff7fffffff
#define ll long long
ll low[N],dfn[N],first[N],head[N],vis[N],col[N],v[N],u[N],w[N],t[N],d[N];
ll n,m,dep,cnt,gro,cot;
struct email
{
    ll u,v,w;
    ll nxt;
}e[N*4],g[N*4];
queue<ll>q;
stack<ll>s;
inline void add(ll u,ll v,ll w)
{
    e[++cnt].nxt=first[u];first[u]=cnt;
    e[cnt].u=u;e[cnt].v=v;e[cnt].w=w;
}

inline void readd(ll u,ll v,ll w)
{
    g[++cot].nxt=head[u];head[u]=cot;
    g[cot].u=u;g[cot].v=v;g[cot].w=w;
}

void spfa(ll x)
{
    q.push(x);vis[x]=1;t[x]=0;d[x]=0;
    while(!q.empty())
    {
        ll u=q.front();q.pop();vis[u]=0;
        for(ll i=head[u];i;i=g[i].nxt)
        {
            ll v=g[i].v,tim=g[i].w,w=e[i].w;
            if(t[v]>t[u]+tim)
            {
                t[v]=t[u]+tim;
                d[v]=d[u]+w;
                if(!vis[v])
                {
                    q.push(v);
                    vis[v]=1;
                }
            }
            if(t[v]==t[u]+tim)
                if(d[v]>d[u]+w)
                {
                    d[v]=d[u]+w;
                    if(!vis[v])
                    {
                        q.push(v);
                        vis[v]=1;
                    }
                    
                }    
        }
    }
}

void tarjan(ll u)
{
    low[u]=dfn[u]=++dep;
    s.push(u);vis[u]=1;
    for(ll i=first[u];i;i=e[i].nxt)
    {
        ll v=e[i].v;
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else
            if(vis[v])
                low[u]=min(low[u],dfn[v]);    
    }
    if(dfn[u]==low[u])
    {
        gro++;
        while(1)
        {
            ll tt=s.top();s.pop();
            col[tt]=gro;
            vis[tt]=0;
            if(tt==u)break;
        }
    }
}

int main()
{
    scanf("%lld%lld",&n,&m);
    for(ll i=1;i<=m;i++)
    {
        scanf("%lld%lld%lld",&u[i],&v[i],&w[i]);
        add(v[i],u[i],w[i]);
    }
    tarjan(1);
    for(ll i=1;i<=m;i++)
    {
        ll u1=u[i],v1=v[i],w1;
        if(col[u1]==col[v1])
            w1=1;
        else
            w1=0;
        readd(v1,u1,w1);
    }

    memset(vis,0,sizeof(vis));
    for(ll i=1;i<=n;i++)
        t[i]=INF,d[i]=INF;
    spfa(1);
    for(ll i=2;i<=n;i++)
    {
        if(t[i]==INF||d[i]==INF)
            printf("-1
");
        else
            printf("%lld %lld
",t[i],d[i]);
    }
    
}
“Make my parents proud,and impress the girl I like.”
原文地址:https://www.cnblogs.com/NSD-email0820/p/9483477.html