[洛谷P4962]朋也与光玉

题目大意:有一张$n(n\leqslant100)$个点$m(m\leqslant n(n-1)$条边的有向图,每个点有一个颜色,需要找到一条长度为$k(k\leqslant13)$,恰好经过全部$k$种颜色的路径。求最短路径

题解:状压$DP$,令$f_{i,S}$表示现在在第$i$个点,颜色状态为$S$的最短路径,要求长度也为$k$,只需要在转移的时候判断一下即可

卡点:

C++ Code:

#include <cstdio>
#define maxn 111
#define maxm (maxn * maxn)
#define N (1 << 13)
const int inf = 0x3f3f3f3f;
inline void getmin(int &a, int b) { if (a > b) a = b; };

int head[maxn], cnt;
struct Edge {
	int to, nxt, w;
} e[maxm];
inline void addedge(int a, int b, int c) {
	e[++cnt] = (Edge) { b, head[a], c }; head[a] = cnt;
}

int n, m, k, ans = inf;
int s[maxn], f[maxn][N];
int main() {
	scanf("%d%d%d", &n, &m, &k);
	__builtin_memset(f, 0x3f, sizeof f);
	for (int i = 1; i <= n; ++i) {
		scanf("%d", s + i);
		f[i][1 << s[i]] = 0;
	}
	for (int i = 0, a, b, c; i < m; ++i) {
		scanf("%d%d%d", &a, &b, &c);
		addedge(a, b, c);
	}
	const int U = 1 << k, I = U - 1;
	for (int j = 1; j < U; ++j) {
		for (int u = 1; u <= n; ++u) if (f[u][j] != inf) {
			for (int i = head[u]; i; i = e[i].nxt) {
				int v = e[i].to;
				if (j >> s[v] & 1) continue;
				getmin(f[v][j | 1 << s[v]], f[u][j] + e[i].w);
			}
		}
	}
	for (int i = 1; i <= n; ++i) getmin(ans, f[i][I]);
	if (ans != inf) printf("%d\n", ans);
	else puts("Ushio!");
	return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/Memory-of-winter/p/10333371.html