hdu 3001(状压dp, 3进制)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3001
由于本题中一个点最多能够访问2次,由此可以联想到3进制;
visited[i][j]表示在状态i下在点j已经做过的次数,dp[i][j]表示在状态i下到达点j走过的最小的路程,于是我们可以通过预处理得到visited[i][j]数组,然后就是一般的状态转移。
1 /************************************************************************* 2 > File Name: hdu3001.cpp 3 > Author: syhjh 4 > Created Time: 2014年03月09日 星期日 14时50分17秒 5 ************************************************************************/ 6 #include <iostream> 7 #include <cstdio> 8 #include <cstring> 9 #include <algorithm> 10 using namespace std; 11 12 const int inf = 0x3f3f3f3f; 13 template < class T > inline T getMIN(const T &a, const T &b) 14 { 15 return a < b ? a : b; 16 } 17 18 int N, M; 19 int dist[12][12]; 20 int State[12]; 21 int dp[60000][12]; //当前状态下在某个点的值 22 int visited[60000][12]; //当前状态i下在点j已经走过的次数 23 24 void Init() 25 { 26 State[0] = 1; 27 for (int i = 1; i <= 10; i++) { 28 State[i] = State[i - 1] * 3; 29 } 30 for (int s = 0; s <= State[10]; s++) { 31 int x = s; 32 for (int i = 0; i <= 10; i++) { 33 visited[s][i] = x % 3; 34 x /= 3; 35 } 36 } 37 } 38 39 int getDP() 40 { 41 int ans = inf; 42 memset(dp, 0x3f, sizeof(dp)); 43 for (int i = 0; i < N; i++) dp[State[i]][i] = 0; 44 for (int s = 0; s < State[N]; s++) { 45 int flag = 1; //用于标记是否所有的点都已经走过 46 for (int i = 0; i < N; i++) { 47 if (visited[s][i] == 0) flag = 0; 48 if (dp[s][i] == inf) continue; 49 for (int j = 0; j < N; j++) if (j != i) { 50 if (visited[s][j] >= 2 || dist[i][j] == inf) continue; 51 dp[s + State[j]][j] = getMIN(dp[s + State[j]][j], dp[s][i] + dist[i][j]); 52 } 53 } 54 if (flag) { 55 for (int i = 0; i < N; i++) { 56 ans = getMIN(ans, dp[s][i]); 57 } 58 } 59 } 60 if (ans == inf) ans = -1; 61 return ans; 62 } 63 64 65 int main() 66 { 67 Init(); 68 while (cin >> N >> M) { 69 memset(dist, 0x3f, sizeof(dist)); 70 while (M--) { 71 int u, v, w; 72 cin >> u >> v >> w; 73 u--, v--; 74 dist[u][v] = dist[v][u] = getMIN(dist[u][v], w); 75 } 76 cout << getDP() << endl; 77 } 78 return 0; 79 }