题意: Mr.Acmer 希望能走遍所有的城市,但他不会进入一个城市超过两次。 每次从一个城市到另一个城市需要一定的消耗,求他总共最少的消耗量。如果他不能在条件允许下走遍所有城市则输出-1。
由数据量可知,城市数量仅为个位数的数量级,非常少。所以可以用状态压缩来做,对每一个城市而言,有三种状态。我们用0表示为走过,1表示走过1次,2表示走过两次。
map[ i ][ j ] 来存储 i 号城市到 j 号城市所需要的消耗。 dp[ i ][ j ] :i 状态下,以 j 号城市为最后落脚点所需的最少消耗量。
dp[ i ][ j ] = min ( dp[ p ][ k ] +map[ k ][ j ] )
预处理出状态 i 下三进制每一位数,存在s[ i ] 中。
#include<iostream>
#include<cstdio>
#include<string.h>
#include<algorithm>
using namespace std;
#define INF 0x1f1f1f1f
int three[11],s[59060][11],dp[59060][11];
int n,m,map[11][11];
void pretreat()//预处理每个状态i : 十进制数换三进制数后每一位数什么
{
int i,p,up;
three[0]=1;
for(i=1;i<11;i++)
{
three[i]=three[i-1]*3;
}
for(i=0;i<three[10];i++)
{
p=i;
up=0;
while(p!=0)
{
s[i][up++]=p%3;
p/=3;
}
}
}
int main()
{
int i,j,k,r;
pretreat();
while(scanf("%d%d",&n,&m)!=EOF)//忘记写!=EOF 我te了16次,还在那不断得各种优化。。我艹。。
{
memset(dp,INF,sizeof(dp));
int x,y;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
map[i][j]=INF;
for(i=0;i<m;i++)
{
scanf("%d%d",&x,&y);
scanf("%d",&map[x-1][y-1]);
map[y-1][x-1]=map[x-1][y-1]=min(map[x-1][y-1],map[y-1][x-1]);
}
for(i=0;i<n;i++)//初始化超人把他送到任意位置开始时的值
{
dp[three[i]][i]=0;
}
dp[0][0]=0;
int ans=INF;
for(i=1;i<three[n];i++)//枚举状态
{
int flag=0;
for(j=0;j<n;j++)//枚举每一个给状态下最后一个到达的点
{
if(s[i][j]==0) flag=1;
if(dp[i][j]==INF) continue;
for(k=0;k<n;k++)//枚举下一个将要到达的点
{
if(j==k||s[i][k]==2||map[j][k]==INF) continue;
int ret=i+three[k];
dp[ret][k]=min(dp[ret][k],dp[i][j]+map[j][k]);
}
}
if(flag==0)
{
for(r=0;r<n;r++)
{
ans=min(ans,dp[i][r]);
}
}
}
if(ans==INF) printf("-1\n");
else printf("%d\n",ans);
}
return 0;
}