ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[HAOI2012] 道路

2021-05-09 22:02:30  阅读:204  来源: 互联网

标签:cnt1 int re SPFA 道路 cnt2 HAOI2012 dis


题面

道路
双倍经验

题解

题意

对于每条道路,求出有多少条最短路经过它。

解析

先看看数据范围,不算大。
所以我们分别以每个点为起点,用 S P F A SPFA SPFA 求出每个点到源点的最短距离。
不难发现对于边 ( u , v , w ) (u,v,w) (u,v,w),如果 d i s [ u ] + w = = d i s [ v ] dis[u] + w == dis[v] dis[u]+w==dis[v],那么这条边一定在源点到 v v v 的最短路上。
而不满足这个条件的边,显然对答案毫无贡献,所以我们可以在跑完最短路后忽略不满足条件的这些边。
这样原图就变成了一副 D A G DAG DAG 图,因为不存在 d i s [ u ] + w = = d i s [ v ] dis[u] + w == dis[v] dis[u]+w==dis[v] ,且 d i s [ v ] + w = = d i s [ u ] dis[v] + w == dis[u] dis[v]+w==dis[u]。
在 D A G DAG DAG 图上我们就可以跑拓扑排序了。对于每个点求出从源点到达它的方案数,再按照拓扑排序的逆序求出从后面的节点到达当前节点的方案数。
原因请看下图:
在这里插入图片描述
从源点到 u u u 的方案数记为 c n t 1 [ u ] cnt1[u] cnt1[u],从后面的节点到达 v v v 的方案数记为 c n t 2 [ v ] cnt2[v] cnt2[v] ,不难发现根据乘法原理,这条从 u u u 到 v v v 的边就有 c n t 1 [ u ] × c n t 2 [ v ] cnt1[u] \times cnt2[v] cnt1[u]×cnt2[v] 条最短路经过了它。因为当前图只保留了在最短路上的边,这些方案数确实都是最短路,所以答案是正确的。

代码

不知道我按照正常的 S P F A SPFA SPFA 的写法为什么只能过 40 40 40 分,这份代码里面的 S P F A SPFA SPFA 的内容是参考了其它题解的写法的。

#include<cstdio>
#include<cstring>
#include<queue>
#define re register

using namespace std;

const int N = 1505,M = 5005;
const int mod = 1e9 + 7;

struct edge {
	int from,next,to,w;
}a[M];
int head[N],dis[N],ans[M],que[M << 1],n,m,a_size = 0;
bool vis[N],is[M];
inline void add(int u,int v,int w) {
	a[++a_size] = (edge){u,head[u],v,w};
	head[u] = a_size;
}
void SPFA(int s) {
    memset(dis,0x3f,sizeof(dis));
    memset(is,0,sizeof(is)); re int len;
    dis[que[len = 1] = s] = 0; vis[s] = true;
    for (re int i = 1; i <= len; i++) {
        int u = que[i]; vis[u] = 0;
        for (re int e = head[u],v; e; e = a[e].next)
            if (dis[u] + a[e].w < dis[v = a[e].to]) {
                dis[v] = dis[u] + a[e].w;
                if (!vis[v]) vis[que[++len] = v] = 1;
            }
    }
    for (re int i = 1; i <= m; i++)
        if (dis[a[i].from] + a[i].w == dis[a[i].to])
            is[i] = 1;
}
int deg[N],cnt1[N],cnt2[N],ord[N],len;
queue<int> q;
void tuopu(int s) {
	while(!q.empty()) q.pop();
	memset(deg,0,sizeof(deg));
	memset(cnt1,0,sizeof(cnt1));
	memset(cnt2,0,sizeof(cnt2)); len = 0;
	for(re int i = 1; i <= m; i++) if(is[i]) deg[a[i].to]++;
	q.push(s); cnt1[s] = 1;
	while(!q.empty()) {
		int x = q.front();
		q.pop(); ord[++len] = x;
		for(int i = head[x]; i; i = a[i].next) {
			if(!is[i]) continue;
			int y = a[i].to;
			cnt1[y] = (cnt1[y] + cnt1[x]) % mod;
			if(--deg[y] == 0) q.push(y);
		}
	}
	for(re int j = len; j >= 1; j--) {
		re int x = ord[j]; cnt2[x]++;
		for(re int i = head[x]; i; i = a[i].next) {
			if(!is[i]) continue;
			cnt2[x] = (cnt2[x] + cnt2[a[i].to]) % mod; 
		}
	}
}
inline int read() {
	re int x = 0,flag = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9'){if(ch == '-')flag = -1;ch = getchar();}
	while(ch >='0' && ch <='9'){x = (x << 3) + (x << 1) + ch - 48;ch = getchar();}
	return x * flag;
}
int main() {
	n = read(),m = read();
	for(re int i = 1,u,v,w; i <= m; i++) {
		u = read(),v = read(),w = read();
		add(u,v,w);
	}
	for(re int i = 1; i <= n; i++) {
		SPFA(i); tuopu(i);
		for(re int j = 1; j <= m; j++)
			if(is[j]) ans[j] = (ans[j] + 1ll * cnt1[a[j].from] * cnt2[a[j].to] % mod) % mod;
	}
	for(re int i = 1; i <= m; i++) printf("%d\n",ans[i]);
	return 0;
}

标签:cnt1,int,re,SPFA,道路,cnt2,HAOI2012,dis
来源: https://blog.csdn.net/init1064573673/article/details/116571091

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有