zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    WinForm 资源文件的使用
    php 常量
    netbean使用技巧
    netbeans 7安装xdebug调试php程序
    eclipse 开发技巧
    asp.net 获取客户机IP地址
    NameValueCollection详解
    Paramics插件编程进程间通讯
    Paramics API编程配置
    windows查询端口占用
  • 原文地址:https://www.cnblogs.com/LukeStepByStep/p/6056451.html
Copyright © 2011-2022 走看看