题意:一个人要旅行,他要去n个地方,且这n个地方每个地方最多可以走2次;
给m条路径,寻问最短花费
很明显的状态压缩,但是要求每个点最多只能走两次,就没办法标记当前点走过或是没走过,只能用三进制来表示
1代表地点1被走过一次、
2代表地点1被走过两次、
3(即10)代表地点2被走过一次、
4(即11)代表地点1被走过一次,地点2被走过一次、
5(即12)代表地点1被走过两次,地点2被走过一次、
附AC代码
#include<stdio.h>
#include<string.h>
int dis[15],dp[80000][15],dpp[80000][15];
int map[15][15];
int min1(int a,int b)
{
if(a<b)
return a;
return b;
}
int main()
{
int i,j,n,m,k;
j=1;
for(i=1;i<=11;i++)
{
dis[i]=j;
j*=3;
}
for(i=0;i<dis[11];i++)
{
k=i;
for(j=1;j<=11;j++)
{
dpp[i][j]=k%3;
k/=3;
}
}
while(scanf("%d%d",&n,&m)!=EOF)
{
int sum;
memset(map,127,sizeof(map));
sum=map[0][0];
int cnt=map[0][0];
while(m--)
{
scanf("%d%d%d",&i,&j,&k);
if(k<map[i][j])//重边
map[j][i]=map[i][j]=k;
}
memset(dp,127,sizeof(dp));
for(i=1;i<=n;i++)
{
dp[dis[i]][i]=0;//
}
for(k=0;k<dis[n+1];k++)
{
int tot=1;
for(i=1;i<=n;i++)
{
if(dpp[k][i]==0) tot=0;
if(dp[k][i]==cnt)continue;
for(j=1;j<=n;j++)
{
if(i==j)continue;//相同的地点不用更新
if(dpp[k][j]>=2)continue;//两次不用更新,因为不能再走了
if(map[i][j]==cnt)continue;//map[i][j]==cnt表示没有从i到j的路故不用更新
int l=k+dis[j];
dp[l][j]=min1(dp[l][j],dp[k][i]+map[i][j]);
}
}
if(tot)
{
for(i=1;i<=n;i++)
{
sum=min1(sum,dp[k][i]);
}
}
}
if(sum==cnt)
sum=-1;
printf("%d\n",sum);
}
return 0;
}