1. 程式人生 > >LOJ#10064. 「一本通 3.1 例 1」黑暗城堡

LOJ#10064. 「一本通 3.1 例 1」黑暗城堡

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;
}