LOJ#10064. 「一本通 3.1 例 1」黑暗城堡
题目描述
你知道黑暗城堡有$N$个房间,$M$条可以制造的双向通道,以及每条通道的长度。
城堡是树形的并且满足下面的条件:
设$D_i$为如果所有的通道都被修建,第$i$号房间与第$1$号房间的最短路径长度;
而$S_i$为实际修建的树形城堡中第$i$号房间与第$1$号房间的路径长度;
要求对于所有整数$i(1\le i\le N)$,有$S_i= D_i$成立。
你想知道有多少种不同的城堡修建方案。当然,你只需要输出答案对$2^{31}-1$取模之后的结果就行了。
输入格式
第一行为两个由空格隔开的整数$N, M$;
第二行到第$M+1$行为$3$个由空格隔开的整数$x, y, l$:表示$x$号房间与$y$号房间之间的通道长度为$l$。
输出格式
一个整数:不同的城堡修建方案数对$2^{31}-1$取模之后的结果。
样例
样例输入
4 6
1 2 1
1 3 2
1 4 3
2 3 1
2 4 2
3 4 1
样例输出
6
样例说明
一共有$4$个房间,$6$条道路,其中$1$号和$2$号,$1$号和$3$号,$1$号和$4$号,$2$号和$3$号,$2$号和$4$号,$3$号和$4$号房间之间的通道长度分别为$1$,$2$,$3$,$1$,$2$,$1$。
而不同的城堡修建方案数对$2^{31} -1$取模之后的结果为$6$。
数据范围与提示
对于全部数据,$1\le N\le 1000$,$1\le M\le \frac{N(N-1)}{2}$,$1\le l\le 200$。
题解Here!
据说标解是最短路径树?但是本蒟蒻不会啊。。。
然后开始$YY$。。。
首先一发最短路没的说。
我直接$SPFA$的,出题人良心,没有卡$SPFA$。
然后把所有可能在生成树上的边提出来。
我们会发现这些边形成了一个$DAG$。
然后对于每个点(除了$1$),我们一定至少有一种选择方案,将它挂在某个节点的下面,成为儿子节点。
所以我们把这些点的选择方案数乘起来就是我们的答案。
而每个点$i$的选择方案就是这个点在$DAG$中的入度$indegree[i]$。
答案可以表示成:$$Ans=\prod_{i=2}^n indegree[i]$$
然后就没了。
记得开$long\ long$。
附代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<queue> #define MAXN 1010 #define MAX 999999999 #define MOD 2147483647LL using namespace std; int n,m,c=1; int head[MAXN],path[MAXN]; long long ans=1,indegree[MAXN]; bool vis[MAXN]; struct Grpah{ int next,to,w; }edge[MAXN*MAXN]; inline int read(){ int date=0,w=1;char c=0; while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();} while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();} return date*w; } inline int relax(int u,int v,int w){ if(path[v]>path[u]+w){ path[v]=path[u]+w; return 1; } return 0; } inline void add_edge(int u,int v,int w){ edge[c].to=v;edge[c].w=w;edge[c].next=head[u];head[u]=c++; edge[c].to=u;edge[c].w=w;edge[c].next=head[v];head[v]=c++; } void spfa(){ int u,v; queue<int> q; for(int i=1;i<=n;i++){path[i]=MAX;vis[i]=false;} path[1]=0; vis[1]=true; q.push(1); while(!q.empty()){ u=q.front(); q.pop(); vis[u]=false; for(int i=head[u];i;i=edge[i].next){ v=edge[i].to; if(relax(u,v,edge[i].w)&&!vis[v]){ vis[v]=true; q.push(v); } } } } void work(){ int u,v,w; for(int i=1;i<c;i+=2){ u=edge[i+1].to;v=edge[i].to;w=edge[i].w; if(path[u]+w==path[v])indegree[v]++; if(path[v]+w==path[u])indegree[u]++; } for(int i=2;i<=n;i++)ans=ans*indegree[i]%MOD; printf("%lld\n",ans); } void init(){ int u,v,w; n=read();m=read(); for(int i=1;i<=m;i++){ u=read();v=read();w=read(); add_edge(u,v,w); } spfa(); } int main(){ init(); work(); return 0; }