拓扑排序 神秘岛

拓扑排序 神秘岛
2017年7月27日
邻接表+拓扑排序+递推


FireDancer来到一个神秘岛,他要从岛的西头到东头然后在东头的码头离开。可是当他走了一次后,发现这个岛的景色非常的美丽,于是他从东头的传送门传到了西头,换了一种走法又走了一遍。发现还不过瘾,又走了一遍……终于,FireDancer把所有的从西头到东头的路径都走了一遍。他站在岛东头的海滩上,突然想到了一个问题,那就是他一共花了多少时间。他把这个问题交给了你。
FireDancer把这个岛抽象成了一个图,共n个点代表路的相交处,m条边表示路,边是有向的(只能按照边的方向行走),且可能有连接相同两点的边。输入保证这个图没有环,而且从西头到东头至少存在一条路径。两条路径被认为是不同的当且仅当它们所经过的路不完全相同。
保证起点是唯一入度为0的点。
Input Format
第一行为5个整数,n、m、s、t、t0,分别表示点数(编号是从1到n),边数,岛西头的编号,岛东头的编号和传送一次的时间。
以后m行,每行3个整数,x、y、t,表示从点x到点y有一条行走耗时为t的路。
且:2<=n<=10000; 1<=m<=50000;t<=10000;t0<=10000
Output Format
若总耗时为total,则输出total mod 10000(total对10000取余)。


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

int N, M, S, T, perT;
#define mod 10000
struct Roads{
    int x, y, v, next;
}E[51000];  int ans = 0;
int V[11000];//每个顶点的第一条边的序号
int inDegree[11000];//邻接表中每个顶点的入度
// 邻接表
int ansR[11000];//达到每个点的路线的个数
int ansT[11000];//能达到每个点的所有路线的总时间

int Que[11000], tail = 0;//Topsort

void AssignEdges(int x, int y, int t)
{
    E[++ans].next = V[x];
    E[ans].x = x;   E[ans].y = y;   E[ans].v = t;
    V[x] = ans;   inDegree[y]++;
}

void Putin()
{
    memset(E, 0, sizeof(E));
    cin >> N >> M >> S >> T >> perT;
    memset(V, -1, sizeof(V));
    memset(inDegree, 0, sizeof(inDegree));
    int xi, yi, ti;
    for(int i = 1; i <= M; i++)
    {
        cin >> xi >> yi >> ti;
        AssignEdges(xi, yi, ti);
    }
    //
    memset(ansR, 0, sizeof(ansR));
    memset(ansT, 0, sizeof(ansT));
}

void Topsort()
{
    for(int i = 1; i <= N; i++)
        if(inDegree[i] == 0)    Que[++tail] = i;
    for(int i = 1; i <= tail; i++){
        for(int k = V[Que[tail]]; k > 0; k = E[k].next){
            inDegree[E[k].y]--;
            if(inDegree[E[k].y] == 0)   Que[++tail] = E[k].y;
        }
        if(tail == N)   return;
    }
}

void Cal()
{
    ansR[S] = 1;    ansT[S] = 0;
    for(int j = 1; j <= N; j++){
        int k = Que[j];
        if(V[k] > 0)
            for(int i = V[k]; i > 0; i = E[i].next)
            {
                ansR[E[i].y] = (ansR[E[i].y] + ansR[k]) % mod;
                ansT[E[i].y] = (ansT[k] + E[i].v * ansR[k] + ansT[E[i].y]) % mod;
                //递推公式
            }
    }
    cout << (ansT[T] + ((ansR[T] - 1) * perT)) % mod << endl;
}

int main()
{
    Putin();
    Topsort();
    Cal();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值