Problem:
E : Arojam's Mask / 仮面

問題文

あなたは勇者である。勇者が旅をしている世界は N 個の街と、異なる街同士を結ぶ M 本の道からなる。道 i は街 a_i と街 b_i を結び、双方向に移動可能である。

街 S から出発し、街 T に移動することが勇者の目的である。 S,T は異なる街である。勇者は 0 日目に街を出発し、ちょうど 1 日かけて 1 本の道を通って移動することができる。道を使った移動には日数の制限 R があり、R 日目を超えることはできない。

また、勇者は任意の街で「オカリナを吹く」こともできる。オカリナを吹くと、時は 0 日目に、位置は街 S に戻される。つまり、R 回を超える移動を行う場合は、最低一度はオカリナを吹かなければならない。

さらに、勇者がある街に位置すると「イベント」が発生することがある。イベントは E 種類あり、i 番目のイベントは、街 c_{i} で発生する。イベントは勇者がそこにいると自動的に発生し、新たに道 a’_i と b’_i を結ぶ道が生じる。この道はオカリナを吹いても消えることはなく、初めから存在する道とも、別のイベントによって追加される道とも重複しない。ある町で起こるイベントは高々1つである。

さて、勇者の今日の仕事は、街 T に到達するまでに必要な移動の回数とオカリナを吹く回数の和の最小値を求めるプログラムを書くことである。

入力

入力は以下の形式で与えられる。

N M E S T R
a_{0} b_{0}
…
a_{M−1} b_{M−1}
a’_{0} b’_{0} c_{0}
…
a’_{E−1} b’_{E−1} c_{E−1}

制約

入力はすべて整数である

2 \≤ N \≤ 100

1 \≤ M+E \≤ N(N−1)/2

0 \≤ E \≤ 4

0 \≤ R \≤ 100

0 \≤ S,T,a_i,b_i,a’_i,b’_i,c_i \≤ N−1

S ≠ T

a_{i} ≠ b_{i}, a’_{i} ≠ b’_{i}

a_{i} と b_{i}、a’_{i} と b’_{i}の全ての組は重複しない

i ≠ j なら c_{i} ≠ c_{j}

出力

答えを一行で出力せよ。どうしても T へ到達できない場合は −1 を出力せよ。

サンプル

サンプル入力1

8 5 2 0 5 5
0 1
0 3
0 6
1 2
6 7
3 4 7
4 5 2

サンプル出力1

9

例えば以下のように移動すればよい。イベントを起こすまでは道(4,5), (3,4)は存在しないことに注意せよ。

街2に行くと4から5へ移動できるようになる

オカリナを使用し0へ戻る

街7に行くと3から4へ移動できるようになる

オカリナを使用し0へ戻る

0から5へまっすぐ進む

サンプル入力2

7 5 1 0 6 8
0 1
1 2
2 3
3 4
4 5
3 6 5

サンプル出力2

8

オカリナを1度も吹かない経路が最適である。

サンプル入力3

4 1 4 1 2 3
3 1
3 2 0
0 1 3
0 3 1
0 2 2

サンプル出力3

5

街 S でイベントが起こることもある。

Solution in C++ (judge verdict: Accepted)

#include <string>
#include <vector>
#include <algorithm>
#include <numeric>
#include <set>
#include <map>
#include <queue>
#include <iostream>
#include <sstream>
#include <cstdio>
#include <cmath>
#include <ctime>
#include <cstring>
#include <cctype>
#include <cassert>
#include <limits>
#include <functional>
#define rep(i,n) for(int (i)=0;(i)<(int)(n);++(i))
#define rer(i,l,u) for(int (i)=(int)(l);(i)<=(int)(u);++(i))
#define reu(i,l,u) for(int (i)=(int)(l);(i)<(int)(u);++(i))
#if defined(_MSC_VER) || __cplusplus > 199711L
#define aut(r,v) auto r = (v)
#else
#define aut(r,v) __typeof(v) r = (v)
#endif
#define each(it,o) for(aut(it, (o).begin()); it != (o).end(); ++ it)
#define all(o) (o).begin(), (o).end()
#define pb(x) push_back(x)
#define mp(x,y) make_pair((x),(y))
#define mset(m,v) memset(m,v,sizeof(m))
#define INF 0x3f3f3f3f
#define INFL 0x3f3f3f3f3f3f3f3fLL
using namespace std;
typedef vector<int> vi; typedef pair<int,int> pii; typedef vector<pair<int,int> > vpii; typedef long long ll;
template<typename T, typename U> inline void amin(T &x, U y) { if(y < x) x = y; }
template<typename T, typename U> inline void amax(T &x, U y) { if(x < y) x = y; }

int main() {
	int N, M, E, S, T, R;
	scanf("%d%d%d%d%d%d", &N, &M, &E, &S, &T, &R);
	vector<vector<bool> > g(N, vector<bool>(N, false));
	rep(i, M) {
		int a, b;
		scanf("%d%d", &a, &b);
		g[a][b] = g[b][a] = true;
	}
	vector<pii> roads(E);
	vi cs(E);
	int initst = 0;
	rep(i, E) {
		int a, b, c;
		scanf("%d%d%d", &a, &b, &c);
		if(c == S)
			initst |= 1 << i;
		roads[i] = mp(a, b);
		cs[i] = c;
	}
	int ans = INF;
	vector<vector<vi> > dp(1 << E, vector<vi>(R+1, vi(N, INF)));
	dp[initst][0][S] = 0;
	rep(i, 1 << E) {
		vector<vi> dist(N, vi(N, INF));
		rep(j, N) {
			vi q, nq; vector<bool> vis(N, false);
			nq.push_back(j);
			vis[j] = true; dist[j][j] = 0;
			while(!nq.empty()) {
				q.swap(nq);
				while(!q.empty()) {
					int k = q.back(); q.pop_back();
					rep(l, N) if(!vis[l] && g[k][l]) {
						vis[l] = true;
						dist[j][l] = dist[j][k] + 1;
						nq.push_back(l);
					}
					rep(e, E) if(i >> e & 1) {
						int a = roads[e].first, b = roads[e].second;
						if(k == b) swap(a, b);
						if(k == a && !vis[b]) {
							vis[b] = true;
							dist[j][b] = dist[j][k] + 1;
							nq.push_back(b);
						}
					}
				}
			}
		}
		rep(j, R+1) rep(k, N) {
			int x = dp[i][j][k];
			if(x == INF) continue;
			rep(l, E) if(~i >> l & 1) {
				int c = cs[l];
				if(j + dist[k][c] <= R)
					amin(dp[i | 1 << l][j + dist[k][c]][c], x + dist[k][c]);
				if(dist[S][c] <= R)
					amin(dp[i | 1 << l][dist[S][c]][c], x + 1 + dist[S][c]);
			}
			if(j + dist[k][T] <= R)
				amin(ans, x + dist[k][T]);
			if(dist[S][T] <= R)
				amin(ans, x + 1 + dist[S][T]);
		}
	}
	if(ans == INF)
		puts("-1");
	else
		printf("%d\n", ans);
	return 0;
}