一开始看成了一个城市最多只旅行一次,还以为是简单题,所以直接DFS,可是一直不对。
后来仔细看,是至少旅行两次,这样用DFS就没法了。
后来查了才知道是TSP问题,用的是DP,其实我也不太会写,先是看了一下别人的原理,代码,
自己也是边写边模仿的吧。,就这样了
原理:这里每个节点的状态可以是已经访问0,1,2次这样的三种状态,所以可以用一个三进制数记录每一个节点的状态。
pre[i][j]表示:在状态i下第j个城市的状态。(节点是由0~n-1的), (这个数组的功能是先计算一次,多次使用,可以节约时间)
dp[i][j]表示:在状态i下最后访问的城市是j。(全部初始化为无穷大,并且只有一个城市的状态的对应的访问的最后城市为0值)
更新方程:dp[next][k]=max(dp[next][k],dp[cur][j]+map[j][k]);
注意:给出的边有重边,直接取重边中的最小边即可
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
const int inf=0x3f3f3f3f;
const int N = 60000;
int dp[N][12],pre[N][12];
int n,m;
int map[12][12];
int s[12];
void init()
{
int i,j,k;
s[0]=1;
for (i=1;i<=12;i++)
s[i]=3*s[i-1];
for (i=0;i<s[10];++i)
{
for (j=0,k=i;j<10;++j)
{
pre[i][j]=k%3;
k/=3;
}
}
}
void DP()
{
int i,j,k;
int ans=inf;
for (i=0;i<n;i++)
dp[s[i]][i]=0;
for (i=0;i<s[n];++i)
{
bool isok=true;
for (j=0;j<n;++j)
{
if (!pre[i][j])
isok=false;
if (dp[i][j]==inf)
continue;
for (k=0;k<n;++k) if (j!=k && pre[i][k]!=2 && map[j][k]!=inf)
{
int next=i+s[k];
dp[next][k]=min(dp[next][k],dp[i][j]+map[j][k]);
}
}
if (isok)
{
for (j=0;j<n;++j)
ans=min(ans,dp[i][j]);
}
}
if (ans!=inf)
cout<<ans<<endl;
else
cout<<-1<<endl;
}
int main()
{
freopen("in.txt","r",stdin);
int i,j,k;
init();
while (cin>>n>>m)
{
memset(map,inf,sizeof(map));
for (i=0;i<s[n];++i)
for (j=0;j<n;j++)
dp[i][j]=inf;
while (m--)
{
cin>>i>>j>>k;
i--;
j--;
map[i][j]=map[j][i]=min(map[i][j],k);
}
DP();
}
return 0;
}