题目注意: 每个点可以经过不超过两次,所以把二进制转换成三进制,就可以很好的存储状态。
dp【i】【j】表示在j状态下,最后一次位置在i点。
还是比较好理解的一个状压dp
#include <iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#include<vector>
#include<queue>
using namespace std;
const int maxn=15;
int ege[maxn][maxn];
int dp[maxn][60000];
int in[maxn];
int vis[maxn];
int n,m;
int get(int x)
{
int num = 0;
for(int i=0; i<n;i++)
{
vis[i] = x%3;
x /= 3;
if(vis[i])
num++;
}
return num;
}
int main()
{
in[0] = 1;
for(int i=1; i<=10; i++)
{
in[i] = in[i-1]*3;
}
while(cin>>n>>m)
{
int ans = 0;
int have_find = 0;
memset(dp,-1,sizeof(dp));
memset(ege,-1,sizeof(ege));
while(m--)
{
int a,b,c;
cin>>a>>b>>c;
ans += c;
a--;
b--;
if(ege[a][b] == -1)
{
ege[a][b] = c;
ege[b][a] = c;
}
else
{
ege[a][b] = min(ege[a][b],c);
ege[b][a] = min(ege[b][a],c);
}
}
ans*=2;
for(int i=1; i<in[n]; i++)
{
int num = get(i);
for(int j=0; j<n; j++)
{
if(vis[j])
{
if(num == 1)
{
dp[j][i] = 0;
}
if(dp[j][i]== -1)
continue;
if(num == n)
{
ans = min(ans, dp[j][i]);
have_find = 1;
continue;
}
for(int k = 0; k < n; k++)
{
//cout<<"now i="<<i<<" j="<<j<<" k="<<k<<" vis[k]="<<vis[k]<<endl;
if(k!=j && vis[k]<2 && ege[k][j]!=-1)
{
int now = i + in[k];
if(dp[k][now] != -1)
dp[k][now] = min(dp[k][now],dp[j][i]+ ege[k][j]);
else
dp[k][now] = dp[j][i]+ ege[k][j];
}
}
}
}
}
// cout<<dp[0][1]<<endl;
// cout<<dp[1][4]<<endl;
if(have_find == 0)
cout<<-1<<endl;
else
cout<<ans<<endl;
}
return 0;
}