码迷,mamicode.com
首页 > 其他好文 > 详细

ACAG 0x01-4 最短Hamilton路径

时间:2019-11-20 23:11:33      阅读:93      评论:0      收藏:0      [点我收藏+]

标签:最短路径   clu   路径   print   name   状压   二进制   最短路   def   

ACAG 0x01-4 最短Hamilton路径

论为什么书上标程跑不过这道题……
首先,这道题与今年CSP-S2的D1T3有着异曲同工之妙,那就是——都有\(O(n!)\)的做法!(大雾)
这道题的正解是状压DP。
对于任意时刻,我们可以使用一个\(n\)位二进制数,若其第\(i\)位为\(1\),则表示第\(i\)个点已经被经过,反之未被经过。因此我们可以使用\(f[i][j]\)表示状态为二进制数\(i\),目前处于点\(j\)时的最短路径。
在起点时,有\(f[1][0]=0\),即只经过了点\(0\),而相应的状态就是只有最低位为\(1\)
记得要把\(f\)数组的其他值均初始化为\(INF\)
不难得到,我们要的最终结果是\(f[(1<<n)-1][n-1]\),即经过所有点(\(i\)的每一位都是\(1\)),处于终点\(n-1\)的最短路。
而本题的状态转移方程为:
\(f[i][j]=min(f[i][j],f[i^(1<<j)][k]+dis[j][k])\) 当且仅当\((i>>j)\&1=1\)\((i>>k)\&1=1\)
其中,因为\(j\)只能被恰好经过一次,且\(k\)也被恰好经过一次,所以考虑所有这样的\(k\)取最小值即可。

#include<bits/stdc++.h>
#define N 20

using namespace std;

int n;
int dis[N][N],f[1<<N][N];

void Read() {
    scanf("%d",&n);
    for(int i=0;i<=n-1;i++) {
        for(int j=0;j<=n-1;j++) {
            scanf("%d",&dis[i][j]);
        }
    }
    return;
}

void Solve() {
    memset(f,0x3f,sizeof(f));
    f[1][0]=0;
    for(int i=1;i<=(1<<n)-1;i++) {
        for(int j=0;j<=n-1;j++) {
            if((i>>j)&1) {
                for(int k=0;k<=n-1;k++) {
                    if((i>>k)&1) {
                        f[i][j]=min(f[i][j],f[i^(1<<j)][k]+dis[j][k]);
                    }
                }
            }
        }
    }
    printf("%d",f[(1<<n)-1][n-1]);
    return;
}

int main()
{
    Read();
    Solve();
    return 0;
}

ACAG 0x01-4 最短Hamilton路径

标签:最短路径   clu   路径   print   name   状压   二进制   最短路   def   

原文地址:https://www.cnblogs.com/luoshui-tianyi/p/11901806.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!