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