2 1 1 2 100 3 2 1 2 40 2 3 50 3 3 1 2 3 1 3 4 2 3 10
100 90 7
因为每个点最多走过两次,所以用三进制进行状态压缩。
#include<iostream>//三进制状态压缩DP
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int bit[11]={1,3,9,27,81,243,729,2187,6561,19683,59049};//一共3的10次方个状态
int dp[60000][12];//第一维代表状态,第二维代表当前位置
int num[60000][12];
int map[12][12];
const int INF=0x3f3f3f3f;
int n,m;
int nmin;
void Three()
{
int i,j,b;
for(i=0;i<=bit[10]-1;i++)
{
b=i;
for(j=0;j<=9;j++)
{
num[i][j]=b%3;
b/=3;
}
}
}
void Init()
{
int i,j;
memset(map,-1,sizeof(map));
for(i=0;i<=bit[n]-1;i++)
{
for(j=0;j<=n-1;j++)
{
dp[i][j]=INF;
}
}
for(j=0;j<=n-1;j++)
{
dp[bit[j]][j]=0;
}
}
void DP()
{
int i,j,flag,k,next;
nmin=INF;
for(i=0;i<=bit[n]-1;i++)
{
flag=1;
for(j=0;j<=n-1;j++)
{
if(num[i][j]==0)
flag=0;
if(dp[i][j]==INF)
continue;
for(k=0;k<=n-1;k++)
{
if(j==k||num[i][k]>=2||map[k][j]==-1)
continue;
next=i+bit[k];
dp[next][k]=min(dp[next][k],dp[i][j]+map[j][k]);
}
}
if(flag)
{
for(j=0;j<=n-1;j++)
{
nmin=min(nmin,dp[i][j]);//该状态下的最优解
}
}
}
return ;
}
int main()
{
int a,b,c;
Three();
while(~scanf("%d%d",&n,&m))
{
Init();
int i,j;
for(i=0;i<=m-1;i++)
{
scanf("%d%d%d",&a,&b,&c);
if(map[a-1][b-1]==-1)
map[a-1][b-1]=map[b-1][a-1]=c;
else map[a-1][b-1]=map[b-1][a-1]=min(map[a-1][b-1],c);
}
DP();
if(nmin==INF) nmin=-1;
printf("%d\n",nmin);
}
return 0;
}
610



被折叠的 条评论
为什么被折叠?



