
哎,题型真的变化无穷啊
先考虑如果每个点只能走一次,那么这就是个典型的状压dp的裸题,
但这时候每个点可以最多走两次,怎么办?
当每个点只能走两次的时候,
我们用二进制的的0表示该点没有被选到,1表示该点被选到
这时候我们就可以用三进制的2表示该点被经过了两次
code(写的很清晰,就是顶格写了,不是很好看):
#include <iostream> #include <string> #include <cmath> #include <cstdio> #include <cstring> #include <cstdlib> #include <ctime> #include <queue> #include <stack> #include <list> #include <algorithm> using namespace std; int pat[12] = {0,1,3,9,27,81,243,729,2187,6561,19683,59049}; int n,m; int edge[11][11]; int idx[59049][11] = {0}; int dp[59049][11]; void initidx() { for(int i = 0 ; i < 59049 ; ++i) { int temp = i ; for(int j = 1 ; j <= 10 ; ++j) { idx[i][j] = temp%3; temp /= 3; if(temp == 0)break; } } } int main() { initidx(); while(~scanf("%d%d",&n,&m)) { memset(edge , 0x3f , sizeof(edge)); memset(dp , 0x3f , sizeof(dp)); for(int i = 0 ; i < m ; ++i) { int a,b,c; scanf("%d%d%d",&a,&b,&c); if(edge[a][b] > c) edge[a][b] = edge[b][a] = c; } for(int i = 1 ; i <= n ; ++i) dp[pat[i]][i] = 0; int ans = 0x3f3f3f3f; for(int i = 0 ; i < pat[n+1] ; ++i) { int complete = 1; for(int j = 1 ; j <= n ; ++j) { if(idx[i][j] == 0) complete = 0; if(dp[i][j] == 0x3f3f3f3f) continue; for(int k = 1 ; k <= n ; ++k) { if(j == k || edge[k][j] == 0x3f3f3f3f || idx[i][k] >= 2)continue; int temp = i + pat[k]; dp[temp][k] = min(dp[temp][k] , dp[i][j] + edge[j][k]); } } if(complete) for(int j = 1 ; j <= n ; ++j) ans = min(ans,dp[i][j]); } if(ans == 0x3f3f3f3f) { puts("-1"); continue; } printf("%d\n",ans); } return 0; }