题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3001
由于本题中一个点最多能够访问2次,由此可以联想到3进制;
visited[i][j]表示在状态i下在点j已经做过的次数,dp[i][j]表示在状态i下到达点j走过的最小的路程,于是我们可以通过预处理得到visited[i][j]数组,然后就是一般的状态转移。
/*************************************************************************
> File Name: hdu3001.cpp
> Author: syhjh
> Created Time: 2014年03月09日 星期日 14时50分17秒
************************************************************************/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; const int inf = 0x3f3f3f3f;
template < class T > inline T getMIN(const T &a, const T &b)
{
return a < b ? a : b;
} int N, M;
int dist[][];
int State[];
int dp[][]; //当前状态下在某个点的值
int visited[][]; //当前状态i下在点j已经走过的次数 void Init()
{
State[] = ;
for (int i = ; i <= ; i++) {
State[i] = State[i - ] * ;
}
for (int s = ; s <= State[]; s++) {
int x = s;
for (int i = ; i <= ; i++) {
visited[s][i] = x % ;
x /= ;
}
}
} int getDP()
{
int ans = inf;
memset(dp, 0x3f, sizeof(dp));
for (int i = ; i < N; i++) dp[State[i]][i] = ;
for (int s = ; s < State[N]; s++) {
int flag = ; //用于标记是否所有的点都已经走过
for (int i = ; i < N; i++) {
if (visited[s][i] == ) flag = ;
if (dp[s][i] == inf) continue;
for (int j = ; j < N; j++) if (j != i) {
if (visited[s][j] >= || dist[i][j] == inf) continue;
dp[s + State[j]][j] = getMIN(dp[s + State[j]][j], dp[s][i] + dist[i][j]);
}
}
if (flag) {
for (int i = ; i < N; i++) {
ans = getMIN(ans, dp[s][i]);
}
}
}
if (ans == inf) ans = -;
return ans;
} int main()
{
Init();
while (cin >> N >> M) {
memset(dist, 0x3f, sizeof(dist));
while (M--) {
int u, v, w;
cin >> u >> v >> w;
u--, v--;
dist[u][v] = dist[v][u] = getMIN(dist[u][v], w);
}
cout << getDP() << endl;
}
return ;
}