Problem 1058 : Winter Bells

解法

やらなければいけないのは、Dijkstra+最短路における、そこまでの経路の数および、そこからゴールまでの経路の数のカウント。


まずは一度Dijkstraして各頂点までの最短距離を求めておく。
次に、各頂点からゴールまでの経路の数は、ゴールから逆にDijkstraして、次の頂点に現在の頂点までの経路の数を足していくDPをすれば求まる。


最後にサンタが通る確率を求める。サンタは全ての経路を等確率で通ることに注意する。
もう一度スタートからDijkstraして、次のノードに、(自分の確率)*(次のノードからゴールへ行く場合の数)/(自分からゴールへ行く場合の数)を足していくDPをすればよい。

ソースコード

int n,m,p,C[100];
vector<vector<pair<int,int> > > e;
int d[100];
bool v[100],u[100];
double togoal[100],prob[100];

int main(){
	while(cin>>n>>m>>p,n){
		e.clear(); e.resize(n);
		rep(i,m){
			int a,b,c; cin>>a>>b>>c;
			e[a].pb(mp(b,c)); e[b].pb(mp(a,c));
		}
		rep(i,p)cin>>C[i];
		
		rep(i,n)d[i]=1<<28; d[0]=0;
		priority_queue<pair<int,int> > Q; Q.push(mp(0,0));
		while(!Q.empty()){
			int c=Q.top().second,cc=Q.top().first; Q.pop();
			if(c==n-1)break;
			if(d[c]<-cc)continue;
			fr(i,e[c])if(d[i->first]>-cc+i->second)
			d[i->first]=-cc+i->second,Q.push(mp(cc-i->second,i->first));
		}
		
		rep(i,n)u[i]=v[i]=0;
		rep(i,n)prob[i]=0,togoal[i]=0;
		togoal[n-1]=1; v[n-1]=1;
		Q=priority_queue<pair<int,int> >(); Q.push(mp(d[n-1],n-1));
		while(!Q.empty()){
			int c=Q.top().second; Q.pop();
			fr(i,e[c])if(d[i->first]+i->second==d[c]){
				togoal[i->first]+=togoal[c];
				if(!v[i->first])v[i->first]=1,Q.push(mp(d[i->first],i->first));
			}
		}
		Q=priority_queue<pair<int,int> >(); Q.push(mp(0,0));
		prob[0]=1; u[0]=1;
		while(!Q.empty()){
			int c=Q.top().second; Q.pop();
			fr(i,e[c])if(v[i->first]&&d[i->first]==d[c]+i->second)
			{
				prob[i->first]+=prob[c]*togoal[i->first]/togoal[c];
				if(!u[i->first])u[i->first]=1,Q.push(mp(-d[i->first],i->first));
			}
		}
		rep(i,p)printf("%.7f\n",prob[C[i]]); puts("");
	}
	return 0;
}