状压DP_POJ 3001(三进制状态压缩)

题目意思很明显,但是和平时的TSP问题有一点点区别,平时的TSP问题,每个点只可以走一次,然后回到我们的起点,但是这个是每个点至多走两次,并且起点是任意的,问题是最短的距离是多少?

这里参考了其他的博客,得知用到了三进制,因为每个点最多可以走两次,所以每个点的状态可以包含0、1、2三种,那么这里位运算就不可以使用了,我们就在程序的开始进行了打表预,处理将每个数的三进制中第i为上的数字都保存在数组digit中,然后就是判断每个点都走过的情况下是暴力每个数都没有0的存在,剩下的就是状态的转移了:

dp[state][i]:状态state下,当前所在的点为i走过的最短的距离

dp[now_state][i] = min(dp[now_state][i] , dp[state][j] + dis[j][i] )

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <algorithm>
#define INF 0x3f3f3f3f
#define LL long long

using namespace std;
const int N = 12;
const int MAXN = 60000;
int n,m;
int dis[N][N];
int dp[MAXN][N];
int three[N],digit[MAXN][N];

void Init()
{//预处理
    three[0] = 1;
    for(int i = 1;i <= 10;i ++) three[i] = three[i-1] * 3;//3^i
    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()
{
    Init();
    while(~scanf("%d%d",&n,&m))
    {
        memset(dis,INF,sizeof(dis));
        memset(dp,INF,sizeof(dp));
        int ans = INF;
        int a,b,c;
        for(int i = 0;i < m;i ++)
        {
            scanf("%d%d%d",&a,&b,&c);
            if(dis[a-1][b-1] > c) dis[a-1][b-1] = dis[b-1][a-1] = c;
        }
        for(int i = 0;i < n;i ++) dp[three[i]][i] = 0;
        for(int S = 0;S < three[n]; S ++)//枚举所有的状态
        {
            bool flag = true;//判断所有的点是否都不为0,不为0,则falg = true,含有0,falg = false;
            for(int i = 0;i < n;i ++)
            {
                if(digit[S][i] == 0) flag = false;
                if(dp[S][i] == INF) continue;
                for(int j = 0;j < n;j ++)
                {
                    if(dis[i][j] != INF && digit[S][j] < 2)//更新状态
                        dp[S+three[j]][j] = min(dp[S+three[j]][j] , dp[S][i] + dis[i][j]);
                }
            }
            if(flag)
            {
                for(int i = 0;i < n;i ++)
                    ans = min(ans,dp[S][i]);
            }
        }
        if(ans == INF)
            printf("-1\n");
        else
            printf("%d\n",ans);
    }
    return 0;
}

参考博客

https://blog.csdn.net/martinue/article/details/50974637

猜你喜欢

转载自blog.csdn.net/li1615882553/article/details/80155655