哎,题型真的变化无穷啊
先考虑如果每个点只能走一次,那么这就是个典型的状压dp的裸题,
但这时候每个点可以最多走两次,怎么办?
当每个点只能走两次的时候,
我们用二进制的的0表示该点没有被选到,1表示该点被选到
这时候我们就可以用三进制的2表示该点被经过了两次
code(写的很清晰,就是顶格写了,不是很好看):
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
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;
}