HDU - 3001 Travelling 【三进制状态压缩+BFS】

版权声明:如需转载,记得标识出处 https://blog.csdn.net/godleaf/article/details/87457847

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3001

状压DP也能做,这里用的是BFS

从搜索的思路来看,这道题的难点就是状态重复访问的情况比较多,到现在我也没明白会有哪些重复访问的状态。

首先题目给出的是10个城市,每个城市都只能被访问两次,所以每一个城市可能访问的次数有0,1,2,三种,所以所有的状态数是3^10,这个数不会很大,而且起点不同,可能出现的情况也会不同,所以每一个城市都要作为起点试一次,所以总共的状态数是(3^10) * 10,这个数字显然即使全部遍历一次也不会超时,但事实上会,而且会超内存,所以在bfs的过程中一定存在状态重复走的情况,这个问题我想了很久,都觉得不太可能出现重复访问状态的情况。但事实就是如此。

既然有重复访问状态的情况,我们就只能把访问过得状态存起来,用来判断当前状态是否走过,以此避免重复放入队列,造成超时和内存超限。

这里的状态主要有三部分组成,访问城市的状态,当前的起点,当前的总消费。为什么是这三个?访问城市的状态相同,起点不同,结果也会大不相同,如果起点也相同,消费不同,情况也会不同。

所以判重的条件应该是:如果访问过 访问城市状态和起点都相同的状态,并且总消费比现在的要小或者等于,就跳过。否则就把这个状态放到队列里面,并且更新状态的总消费。

一开始想图个方便用  map<string, pair<int, int> > 来存三个部分的数据,但是不管怎么优化其他的部分,就是会超时,所以用数组存相应的数据,要用时随取随用,这才AC了。

#include <iostream>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <cstdio>
#include <cmath>
#include <algorithm>

using namespace std;

const int INF = 0x3f3f3f3f;
const int Maxn = 4e5+10;

struct Node {
    int cur, cost, stat;
};

int cost[15][15], N, M, ans, sum[60000][12], u0[12];
int state[60000][12];
queue<Node> qu;

void bfs(int v) {
    while(!qu.empty()) qu.pop();
    Node tmp;
    tmp.cost = 0; tmp.cur = v;
    tmp.stat = u0[v];
    qu.push(tmp);

    bool ok;
    while (!qu.empty()) {
        tmp = qu.front(); qu.pop();
        ok = true;
        for(int i = 1; i <= N; ++i) {
            if(state[tmp.stat][i] == 0) {
                ok = false; break;
            }
        }
        if(ok) {
           ans = min(ans, tmp.cost); continue;
        }

        for(int i = 1; i <= N; ++i) {
            if(i == tmp.cur || state[tmp.stat][i] > 1 || cost[tmp.cur][i] == -1) continue;
            Node now = tmp;
            now.stat += u0[i];
            now.cur = i; now.cost += cost[tmp.cur][i];
            if(now.cost >= ans) continue;
            if(sum[now.stat][now.cur] != 0 && sum[now.stat][now.cur] <= now.cost) continue;
            sum[now.stat][now.cur] = now.cost;
            qu.push(now);
        }
    }
}

void init() {
    for(int i = 1; i <= 11; ++i) u0[i] = pow(3, i-1);
    memset(state, 0, sizeof(state));
    for(int i = 1; i < u0[11]; ++i) {
        int tmp = i, p = 1;
        while (tmp) {
            state[i][p++] = tmp%3;
            tmp /= 3;
        }
    }
}

int main(void)
{
    init();
    while (scanf("%d%d", &N, &M) != EOF) {
        memset(cost, -1, sizeof(cost));
        memset(sum, 0, sizeof(sum));
        int u, v, c;
        for(int i = 0; i < M; ++i) {
            scanf("%d%d%d", &u, &v, &c);
            if(cost[u][v] == -1) cost[u][v] = cost[v][u] = c;
            else cost[u][v] = cost[v][u] = min(cost[u][v], c);
        }
        ans = INF;
        for(int i = 1; i <= N; ++i) bfs(i);

        if(ans == INF) printf("-1\n");
        else printf("%d\n", ans);
    }
	return 0;
}

猜你喜欢

转载自blog.csdn.net/godleaf/article/details/87457847