Datahub
数据改变生活

Rhizomys

发表时间:2022-10-27 20:26

Rhizomys

描述

竹鼠养殖场有若干个小房间,有很多条双向道路连接着它们。

值得注意的是,在养殖场中,连接两个房间的道路可能不止一条。由于路上能看到的风景不同,我们认为这两条路是不同的。

同时,也可能存在一条道路是从一个房间出发又回到它自身,但我们规定,从一个房间到它自己的最短距离为 0。

为了不被吃掉,竹鼠们决定开始运动,运动的方式是从一个小房间经过若干个小房间(中间经过的房间数可以为 0)走到另一个小房间。

但竹鼠们也希望在锻炼过程中尽可能地偷懒,这意味着,竹鼠运动的路线总是沿最短路的。

现在,竹鼠们希望知道从 1 号房间分别到其他所有房间的运动路线的种数。由于它们害怕会因为写代码而被吃掉,所以它们找到了你帮忙。

输入

第一行是两个整数 N,MN,M,表示房间个数和连接房间的道路的条数。

接下来 mm 行,每行三个整数 u,v,cu,v,c,表示 uu 号房间与 vv 号房间之间存在一条长度为 cc 的双向道路。

输出 NN 行,第 ii 行表示从 11 号房间到 ii 号房间的运动路径的种数,由于答案可能会很大,你只需要输出它模 911814911814 的结果。

当不存在任何一条从 11 号房间到i 号房间的道路时,请输出 00。

输入样例 1

输样例 1

样例 1 解释

以下用 EiEi 表示输入中的第 ii 条边。到 1 的最短路长度为 0,只有 1 条。

到 2 的最短路长度为 2,有 2 条( E1E1 , E10E10 )。到 3 的最短路长度为 3,只有 1 条( E3E3 -> E5E5 )。到 4 的最短路长度为 4,有 3 条

( E3E3 -> E7E7 , E1E1 -> E2E2 , E10E10 -> E2E2 )。

到 5 的最短路长度为 1,只有 1 条( E9E9 )。到 6 的最短路长度为 2,只有 1 条( E3E3 )。

输入样例 2

点此下载。

限制

对于 20%的数据,1≤n≤100,1≤m≤20001≤n≤100,1≤m≤2000;

对于 50%的数据,1≤n≤1000,1≤m≤1500001≤n≤1000,1≤m≤150000; 对于 100%的数据,

1≤n≤20000,1≤m≤500000,1≤u,v≤n,1≤c≤101≤n≤20000,1≤m≤500000,1≤u,v≤n

,1≤c≤10。

提示

[这道题统计最短路的数目,我们不妨考虑将所有处在最短路上的边提出来]

[提出这些边后形成了原图的一张子图,显然这张子图是不会有环的,否则与最短路的定义矛盾]

[既然没有环,那我们就可以愉快地做动态规划啦~]

[请同学们思考,如果使用 dijkstra 算法,需要先求最短路,再拓扑排序吗?]

代码

#include <iostream> #include<vector> #include<queue> #include<vector> #include<stack> #include<string.h>

#pragma warning(disable:4996) using namespace std;

// ================= 代码实现开始 =================

int Dist[20000];

long long State[20000]; bool   outQ[20000]; const int mo = 911814;

/* 请在这里定义你需要的全局变量 */ struct QMember

{

int node;

int Dist;

int friend operator > (QMember s1, QMember s2) {

return s1.Dist > s2.Dist;

}

};

struct Edge

{

Edge *next=nullptr;//该点所拥有的下一条边

int go=0;//该点所指向的节点号

int cost;//边的权值

};

Edge *Head[20000]; QMember Node[20000];

priority_queue<QMember,vector<QMember>,greater<QMember>> Q;

// 给定n个点m条边的无向图,求1到其余每个点的最短路的数目

// n:如题意

// m:如题意

// U:大小为m的数组,表示m条无向边中的一个端点

// V:大小为m的数组,表示m条无向边中的另一个端点

// C:大小为m的数组,表示m条无向边的长度

void getAnswer(int n, int m, vector<int> U, vector<int>V, vector<int>C) {

/* 请在这里设计你的算法 */

memset(Dist, 999999, sizeof(Dist));

//初始化点的序号

for (int i = 0; i < n+1; i++)

{

Head[i] = new Edge();

Node[i].node = i;

}

//处理相邻的点及其边

int i = 0;

while (i<m)

{

int u = U[i];

int v = V[i];

int c = C[i];

if (u == v)

{

i++;

continue;

}

//若u或v为1,说明此时应该将相邻点压入Q中以循环

if (u == 1)

{

if (Dist[v] == c)

State[v]++;

else if (Dist[v] > c)

{

Dist[v] = c;

State[v] = 1;

Node[v].Dist = c;

Q.push(Node[v]);

}

}

if (v == 1)

{

if (Dist[u] == c)

State[u]++;

else if (Dist[u] > c)

{

Dist[u] = c;

State[u] = 1;

Node[u].Dist = c;

Q.push(Node[u]);

}

}

if(Head[u]->go==0)//若Head[u]->go==0说明v是u的第一条边所指向的节点

{

Head[u]->go = v;

Head[u]->cost = c;

}

else

{

Edge *ed = new Edge();

ed->go = v;

ed->cost = c;

ed->next = Head[u]->next;

Head[u]->next = ed;

}

if (Head[v]->go == 0)//若Head[u]->go==0说明v是u的第一条边所指向的节点

{

Head[v]->go = u;

Head[v]->cost = c;

}

else

{

Edge *ed = new Edge();

ed->go = u;

ed->cost = c;

ed->next = Head[v]->next;

Head[v]->next = ed;

}

i++;

}

outQ[1] = true;

Dist[1] = 0;

State[1] = 1;

while (!Q.empty())

{

//Qtop:堆顶元素

QMember QTop = Q.top();

Q.pop();

//curNode:当前堆顶的点

//curDist:1->curNode的最短长度

//curState:1->curNode的最短数目

int curNode = QTop.node, curDist = Dist[curNode], curState = State[curNode];

//如果curNode已经用于更新过,则跳过;否则打上出队标记

if (outQ[curNode])

continue;

else

outQ[curNode] = true;

//枚举每一条与curNode相连的边

//Head[curEdge]为curNode的第一条边

for (Edge *curEdge = Head[curNode]; curEdge != nullptr; curEdge = curEdge->next)

{

//nextNode:当前与curNode相连的边的另一个端点

int nextNode = curEdge->go;

//如果从1沿最短路到curNode,再到nextNode的路与原来的方案长度相同时

//以下if中的内容暂定,可能会有错误

if (Dist[nextNode] == curDist + curEdge->cost)

{

State[nextNode] += State[curNode];

if (State[nextNode] > mo)

State[nextNode] % mo;

}

else if (Dist[nextNode] > curDist + curEdge->cost)

{

Dist[nextNode] = curDist + curEdge->cost;

State[nextNode] = State[curNode];

Node[nextNode].Dist = Dist[nextNode];

Q.push(Node[nextNode]);//由于更新了新的最短路径,故原先nextNode所到其

他点的距离也需要更新

}

}

}

for (int i = 1; i <= n; i++)

{

printf("%d\n", State[i]);

}

return;

}

// ================= 代码实现结束 =================

int main() {

int n, m;

scanf("%d%d", &n, &m);

vector<int> U, V, C;

for (int i = 0; i < m; ++i) {

int u, v, c;

scanf("%d%d%d", &u, &v, &c);

U.push_back(u);

V.push_back(v);

C.push_back(c);

}

getAnswer(n, m, U, V, C);

return 0;

}


下一篇n 皇后
文章分类: 数据结构例题
分享到:
QQ:258506508                                     联系电话:020-000000    000-000000                                   联系邮箱:xxx@.co.m                                     联系地址:XXX省XXX市XXX县XXX路