hdu-3001 三进制状态压缩+dp

用dp来求最短路,虽然效率低,但是状态的概念方便解决最短路问题中的很多限制,也便于压缩以保存更多信息。

本题要求访问全图,且每个节点不能访问两次以上。所以用一个三进制数保存全图的访问状态(3^10,空间是足够的),用dp[z+bit[j]][j]=dp[z][i]+ct[i][j]就可以表示,从上一状态以i为结束点,转移到把j加入路径末端后的状态(感叹一下位运算的神奇)。

//
//  main.cpp
//  hdu_3001
//
//  Created by Luke on 2016/11/12.
//  Copyright © 2016年 Luke. All rights reserved.
//

#include <iostream>
#include <cmath>
#include <algorithm>

#include <cstdio>
#define N 15
#define zip 70000
#define INF 919900000//原来要开这么大哇
using namespace std;
int n,m;
int ct[N][N];//存边权
int dp[zip][N];//z状态下,以j为终点的路径费用
int bit[20];
void addE(int from,int to,int fee);
void ini();
int digit(int num,int pos);//返回压缩后的当前位置状态
int solve()
{
    int ans=INF;
    for(int z=0;z<bit[n];z++)
    {
        int f=1;
        for(int j=0;j<n;j++)//表示以j结尾,从位置i转移过来
        {
            int fix=digit(z,j);
            if(fix==2) continue;
            if(fix==0) f=0;
            //if(dp[z][j]==INF) continue;
            for(int i=0;i<n&&z+bit[j]<bit[n];i++)
                dp[z+bit[j]][j]=min(dp[z+bit[j]][j],dp[z][i]+ct[i][j]);
        }
        if(f)//如果是合法状态,就更新一遍ans
            for(int i=0;i<n;i++)
                ans=min(ans,dp[z][i]);
    }
    if(ans==INF)
        return -1;
    return ans;
}
int main(int argc, const char * argv[]) {
    cin.sync_with_stdio(false);
    bit[0]=1;
    for(int i=1;i<=15;i++)
        bit[i]=bit[i-1]*3;
    while(cin>>n>>m)
    {
        int a,b,c;
        ini();
        
        for(int i=0;i<m;i++)
            cin>>a>>b>>c,addE(a,b,c);
        cout<<solve()<<endl;
    }
    
    return 0;
}
void addE(int from,int to,int fee)
{
    from--,to--;//为了节约空间,节点从0开始计数
    ct[from][to]=ct[to][from]=min(ct[to][from],fee);
}
void ini()
{
    for(int i=0;i<N;i++)
        for(int j=0;j<N;j++)
            ct[i][j]=INF;
    for(int i=0;i<zip;i++)
        for(int j=0;j<N;j++)
        {
            if(bit[j]==i)
                dp[i][j]=0;
            else
                dp[i][j]=INF;
        }
}
int digit(int num,int pos)
{
    for(int i=0;i<pos;i++)
        num/=3;
    return num%3;
}
原文地址:https://www.cnblogs.com/LukeStepByStep/p/6056451.html