https://vjudge.net/problem/HDU-3001
题意:题意:Mr ACMer想要进行一次旅行,他决定访问n座城市。Mr ACMer 可以从任意城市出发,必须访问所有的城市至少一次,并且任何一个城市访问的次数不能超过2次。n座城市间有m条道路,每条道路都有一个费用。求Mr ACMer 完成旅行需要花费的最小费用。如果不能完成旅行,则输出-1。
思路:每个点最多只能被访问2次,用3进制来压缩状态,0,1,2分别表示走该点0,1,2次.要注意枚举点的时候,路径和点的对应关系.
假设有3个城市 1 1 0表示前2个城市被访问了1次,第3个城市还没被访问,化成十进制就是12(这里是3进制化化十进制)
详细可见代码
与该题https://blog.csdn.net/qq_38924883/article/details/82987663 有类似之处。
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
int dp[60000][12];
int cost[12][12];
int three[12];
int digit[60000][12];///digit[i][j]表示状态为i,第j为是多少(0,1,2),也就是在状态i下,从第1个城/
市到第10个城市分别被访问了几次,这里n最多只能取到10;
void init()
{
three[0]=1;
for(int i=1;i<=10;i++)
three[i]=three[i-1]*3;
for(int i=0;i<three[10];i++)
{
int temp=i;
for(int j=0;j<10;j++)
{
digit[i][j]=temp%3;
temp/=3;
}
}
}
int main()
{
ios::sync_with_stdio(false);
init();
int n,m;
while(cin>>n>>m)
{
memset(cost,inf,sizeof(cost));
for(int i=0;i<three[n];i++)
for(int j=0;j<n;j++)
dp[i][j]=inf;
while(m--)
{
int u,v,w;
cin>>u>>v>>w;
cost[u-1][v-1]=cost[v-1][u-1]=min(cost[u-1][v-1],w);
}
for(int i=0;i<n;i++)
dp[three[i]][i]=0;
///dp[i][j]的意思为 在状态i下,最后走到的城市为第j个城市.
int ans=inf;
for(int i=0;i<three[n];i++)///枚举状态
{
bool flag=1;
for(int j=0;j<n;j++)///枚举最后到达的城市
{
if(digit[i][j]==0) flag=0;///如果最后到达的城市是走过的话那么就可以更新一次答案
if(dp[i][j]!=inf)///保证是从起点出发
for(int k=0;k<n;k++)
if(cost[j][k]!=inf&&digit[i][k]!=2)///j到k之间是有路的,而且k城市没有被访问2次
{
dp[i+three[k]][k]=min(dp[i+three[k]][k],dp[i][j]+cost[j][k]);
///最后访问的城市就变成了k
}
}
if(flag)
{
for(int j=0;j<n;j++)
ans=min(ans,dp[i][j]);
}
}
if(ans>=inf) cout<<-1<<endl;
else cout<<ans<<endl;
}
return 0;
}