Codeforces Round #321 (Div. 2) Kefa and Dishes 状压+spfa
原题链接:http://codeforces.com/contest/580/problem/D
题意:
给你一些一个有向图,求不超过m步的情况下,能获得的最大权值和是多少,点不能重复走。
题解:
令$dp[u][s]$为在节点u的时候状态是s的最大值。利用spfa的松弛操作来转移。
代码:
#include<iostream> #include<cstring> #include<vector> #include<algorithm> #include<queue> #define MAX_S 1<<19 #define MAX_N 22 using namespace std; typedef long long ll; struct edge { public: int to; ll cost; edge(int t, ll c) : to(t), cost(c) { } edge() { } }; vector<edge> G[MAX_N]; ll g[MAX_N][MAX_N]; ll a[MAX_N]; int n,m,k; int ones[MAX_S]; ll dp[MAX_N][MAX_S]; struct node { public: ll s; int u; node(ll ss, int uu) : s(ss), u(uu) { } node() { } }; queue<node> que; bool inQue[MAX_N][MAX_S]; int main() { cin.sync_with_stdio(false); cin >> n >> m >> k; for (int i = 0; i < (1 << n); i++) { int x = i; while (x)ones[i] += (x & 1), x >>= 1; } for (int i = 0; i < n; i++) cin >> a[i]; for (int i = 0; i < k; i++) { int x, y; ll c; cin >> x >> y >> c; x--, y--; g[y][x] = c; } for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) G[i].push_back(edge(j, g[i][j])); ll ans = 0; for (int i = 0; i < n; i++) { dp[i][1 << i] = a[i]; que.push(node(1 << i, i)); inQue[i][1 << i] = 1; } while (!que.empty()) { node now = que.front(); que.pop(); ll s = now.s; int u = now.u; inQue[u][s] = 0; for (int i = 0; i < G[u].size(); i++) { int v = G[u][i].to; ll c = G[u][i].cost; if (s & (1 << v))continue; ll ns = s | (1 << v); if (ones[ns] > m)continue; if (dp[v][ns] < dp[u][s] + a[v] + c) { dp[v][ns] = dp[u][s] + a[v] + c; que.push(node(ns, v)); inQue[v][ns] = 1; } } } for (int i = 0; i < n; i++) for (int s = 0; s < (1 << n); s++) if (ones[s] == m) ans = max(ans, dp[i][s]); cout << ans << endl; return 0; }