[OpenJ_Bailian - 4124 海贼王之伟大航路] DFS+二进制状态压缩 / 状压DP

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/ACMore_Xiong/article/details/52117115

[OpenJudge 4124 海贼王之伟大航路] 二进制状态压缩+记忆化DFS/ 状压DP

题目链接[OpenJ_Bailian - 4124 海贼王之伟大航路] 

题意:N个顶点之间构成无向图。求遍历所有顶点一次的情况下,从1~N的最短路长度。(2 < N ≤ 16)

分析

思路一  记忆化DFS

直接暴力DFS肯定不行,时间复杂度是(N - 2)! 。然后就想利用状态剪枝。  用dp[u][state] 表示从1~u,中间已经经过的每个点对应state一位二进制位 的最小的距离。 如果遍历到u 的距离小于dp[u][state],就可以进行剪枝了。

思路二 状压DP:

dp[u][state] = min(dp[u][state], dp[i][state ^ (1<<(i - 1))] + G[u][i]);

/**
 *  思路一:记忆化DFS
 */
#include <ctime>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;

//#pragma comment(linker, "/STACK:1024000000,1024000000")

#define FIN             freopen("input.txt","r",stdin)
#define FOUT            freopen("output.txt","w",stdout)
#define fst             first
#define snd             second

//typedef __int64  LL;
//typedef long long LL;
typedef unsigned int uint;
typedef pair<int, int> PII;

const int INF = 0x3f3f3f3f;
const int MAXN = 16 + 5;

int N;
int G[MAXN][MAXN];
int dp[MAXN][ (1 << 16) + 5];
int cnt, finish;
void dfs (int u, int d, int state) {
//    cnt++;
    if (u == N) {
        if (u == N && state == finish) dp[N][state] = min (dp[N][state], d);
        return;
    }
    if (d >= dp[u][state] || d >= dp[N][finish]) return;
    dp[u][state] = d;
    int v, f;
    for (v = 2, f = 2; v < N; v++, f <<= 1) {
        if (state & f) continue;
        dfs (v, d + G[u][v], state | f);
    }
    if (state == (finish ^ f)) dfs (v, d + G[u][v], state | f);
    return;
}

int main() {
#ifndef ONLINE_JUDGE
    FIN;
#endif // ONLINE_JUDGE
//    clock_t start, end;
//    start = clock();
    while (~scanf ("%d", &N) ) {
        for (int i = 1; i <= N; i++) {
            for (int j = 1; j <= N; j++) {
                scanf ("%d", &G[i][j]);
            }
        }
        finish = (1 << N) - 1;
        memset (dp, INF, sizeof (dp) );
        cnt = 0;
        dfs (1, 0, 1);
//        cout << cnt << "\t";
        printf ("%d\n", dp[N][finish]);
    }
//    end = clock();
//    printf ("time=%f\n", (double) (end - start) / CLK_TCK);
    return 0;
}
/**
 *  思路二:状压DP
 */
#include <ctime>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;

//#pragma comment(linker, "/STACK:1024000000,1024000000")

#define FIN             freopen("input.txt","r",stdin)
#define FOUT            freopen("output.txt","w",stdout)
#define fst             first
#define snd             second

//typedef __int64  LL;
//typedef long long LL;
typedef unsigned int uint;
typedef pair<int, int> PII;

const int INF = 0x3f3f3f3f;
const int MAXN = 16 + 5;

int N;
int G[MAXN][MAXN];
int dp[MAXN][ (1 << 16) + 5];
int finish;

int main() {
#ifndef ONLINE_JUDGE
    FIN;
#endif // ONLINE_JUDGE
//    clock_t start, end;
//    start = clock();
    while (~scanf ("%d", &N) ) {
        for (int i = 1; i <= N; i++) {
            for (int j = 1; j <= N; j++) {
                scanf ("%d", &G[i][j]);
            }
        }
        finish = (1 << N) - 1;
        memset (dp, INF, sizeof (dp) );

        dp[1][1] = 0;
        for (int k = 1; k <= finish; k++) {
            for (int i = 1, fi = 1; i <= N; i++, fi <<= 1) {
                if (! (k & fi) ) continue;
                for (int j = 1, fj = 1; j <= N; j++, fj <<= 1) {
                    if (i == j || ! (k & fj) ) continue;
                    dp[i][k] = min (dp[i][k], dp[j][k ^ fi] + G[j][i]);
                }
            }
        }
        printf ("%d\n", dp[N][finish]);
    }
//    end = clock();
//    printf ("time=%f\n", (double) (end - start) / CLK_TCK);
    return 0;
}

 

展开阅读全文

没有更多推荐了,返回首页