[洛谷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; }