现在的位置: 首页 > 综合 > 正文

POJ 3411 Paid Roads (最短路 + dp)

2018年01月14日 ⁄ 综合 ⁄ 共 1459字 ⁄ 字号 评论关闭

题目类型  搜索题 (最短路 + dp)

题目意思
给出 n 个点 m 条边 ( 1 <= n, m <= 10)
其中 每条边由 5 个变量 Ai, Bi, Ci ,Pi, Ri 描述  表示从 Ai 到 Bi 如果到达 Ai 时经过了 Ci 的话就需要花费 Pi 如果没经过 ci的话就花费 Ri
现在问从 1 到 n 最少花费
解题方法
SPFA + 状态压缩dp
用数组 dp[i][j] 表示 到达 i 的时候经过了点集 j 的最少花费
然后结合 SPFA 的求解过程, 根据 点集中是否存在 Ci 判断边的花费 最终可扫描一次 dp[n][0] -> dp[n][(1<<n)-1] 找出最优解  (具体看代码)
参考代码 - 有疑问的地方在下方留言 看到会尽快回复的
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>

using namespace std;

const int INF = 1<<30;
int dp[20][1100];
int n;
vector<int>M[20];
vector<int>J[20];
vector<int>P[20];
vector<int>R[20];

void SPFA() {
	for( int i=1; i<=n; i++ ) for( int j=0; j<(1<<n); j++ ) dp[i][j] = INF;
	dp[1][1] = 0;
	queue<int>q;
	q.push(1);
	bool vis[20];
	memset(vis, 0, sizeof(vis));
	vis[1] = 1;
	while(!q.empty()) {
		int f = q.front(); q.pop();
		vis[f] = 0;
		for( int i=0; i<M[f].size(); i++ ) { // 更新与 f 相邻的点
			int v = M[f][i];
			int c = J[f][i];
			for( int j=0; j<(1<<n); j++ ) { // 用 dp[f][j] 去更新其他状态
				if((j & (1<<(f-1)))==0) continue;
				if((j & (1<<(c-1)))) { // 如果经过了 c 花费就是 P[f][i]
					if(dp[v][j|(1<<(v-1))] > dp[f][j] + P[f][i]) {
						dp[v][j|(1<<(v-1))] = dp[f][j] + P[f][i];
						if(vis[v] == 0) {
							q.push(v);
							vis[v] = 1;
						}
					}
				}
				else { // 否则花费是 R[f][i]
					if(dp[v][j|(1<<(v-1))] > dp[f][j] + R[f][i]) {
						dp[v][j|(1<<(v-1))] = dp[f][j] + R[f][i];
						if(vis[v] == 0) {
							q.push(v);
							vis[v] = 1;
						}
					}
				}
			}
		}
	}
}

int main() {
	//freopen("in", "r", stdin);
	int m;
	while(scanf("%d%d", &n, &m) != EOF) {
		for( int i=0; i<m; i++ ) {
			int a, b, c, p, r;
			scanf("%d%d%d%d%d", &a, &b, &c, &p, &r);
			M[a].push_back(b);
			J[a].push_back(c);
			P[a].push_back(p);
			R[a].push_back(r);
		}
		SPFA();
		int ans = INF;
		for( int i=0; i<(1<<n); i++ ) {
			if((i & 1) && (i & (1<<(n-1)))) {
				ans = min(ans, dp[n][i]);
			}
		}
		if(ans == INF) printf("impossible\n");
		else printf("%d\n", ans);
	}
	return 0;
}

抱歉!评论已关闭.