题目链接:http://lightoj.com/volume_showproblem.php?problem=1406
思路:首先可以预处理出在每个顶点的状态的合法状态vis[u][state], 然后标记那些合法状态mark[state]。最后就是记忆化搜索了,对于当前状态state,我们有res = min(res, 1 + Solve(state ^ substate)), 其中substate为state的子状态,并且substate = (substate - 1) & state.那么最终就是要求Solve((1 << n) - 1)了。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 using namespace std; 7 8 int n, m; 9 bool vis[16][1 << 16]; 10 bool mark[1 << 16]; 11 int dp[1 << 16]; 12 vector<int > g[16]; 13 14 void dfs(int u, int state) 15 { 16 vis[u][state] = true; 17 mark[state] = true; 18 for (int i = 0; i < (int)g[u].size(); i++) { 19 int v = g[u][i]; 20 if (!vis[v][state | (1 << v)]) { 21 dfs(v, state | (1 << v)); 22 } 23 } 24 } 25 26 int Solve(int state) 27 { 28 if (state == 0) return 0; 29 if (dp[state] != -1) return dp[state]; 30 int res = 16; 31 for (int i = state; i > 0; i = (i - 1) & state) { 32 if (mark[i]) { 33 res = min(res, 1 + Solve(state ^ i)); 34 } 35 } 36 return dp[state] = res; 37 } 38 39 40 int main() 41 { 42 int _case, t = 1; 43 scanf("%d", &_case); 44 while (_case--) { 45 scanf("%d %d", &n, &m); 46 for (int i = 0; i < n; i++) g[i].clear(); 47 while (m--) { 48 int u, v; 49 scanf("%d %d", &u, &v); 50 u--, v--; 51 g[u].push_back(v); 52 } 53 memset(vis, false, sizeof(vis)); 54 memset(mark, false, sizeof(mark)); 55 for (int i = 0; i < n; i++) dfs(i, 1 << i); 56 memset(dp, -1, sizeof(dp)); 57 printf("Case %d: %d\n", t++, Solve((1 << n) -1)); 58 } 59 return 0; 60 }