tsp学习

https://onlinejudge.u-aizu.ac.jp/problems/DPL_2_A
假设起点是0

dfs

s t a t e state state是一个 b i t b o a r d bitboard bitboard,比如 0011 0011 0011表示访问过第 0 , 1 0,1 0,1个节点
d p [ s t a t e ] [ u ] dp[state][u] dp[state][u]表示已经访问过了 s t a t e state state中的节点,现在在 u u u点,访问剩下所有的节点,最后到0所需要的代价
显然转移方程 d p [ s t a t e ] [ v ] = min ⁡ ( d p [ s t a t e ∪ { u } ] [ u ] + d i s t [ v ] [ u ] ∣ u ∉ s t a t e ) dp[state][v]=\min\left(dp[state\cup\left\{u\right\}][u]+dist[v][u]|u\notin state\right) dp[state][v]=min(dp[state{u}][u]+dist[v][u]u/state)

#include<cstdio>
#include<cstring>
const int N = 15, INF = 0x3f3f3f3f;
//dp[state][u]访问过state中所有的节点,现在在u,访问剩下所有的节点,最后到0所需要的代价
int dp[1 << N][N], dist[N][N], n;
int tsp(int state, int v) {
	if (dp[state][v] != -1) {
		return dp[state][v];
	}
	if (state + 1 == (1 << n)) {
		if (0 == v) {
			dp[state][v] = 0;
		}
		else {
			dp[state][v] = INF;
		}
		return dp[state][v];
	}
	int res = INF;
	for (int u = 0; u < n; ++u) {
		if (0 == ((state >> u) & 1)) {//u not in  state
			//dp[state][v]=min(dp[state∪u][u]+dist[j][u])
			int temp = tsp(state | (1 << u), u) + dist[v][u];
			if (temp < res) {
				res = temp;
			}
		}
	}
	dp[state][v] = res;
	return res;
}
int main() {
	int e;
	scanf("%d%d", &n, &e);
	memset(dist, INF, sizeof(dist));
	memset(dp, -1, sizeof(dp));
	while (e--) {
		int s, t, d;
		scanf("%d%d%d", &s, &t, &d);
		dist[s][t] = d;
	}
	int res = tsp(0, 0);
	if (res == INF)res = -1;
	printf("%d\n", res);
	return 0;
}

dp

倒序

s t a t e state state是一个 b i t b o a r d bitboard bitboard,比如 0011 0011 0011表示访问过第 0 , 1 0,1 0,1个节点
d p [ s t a t e ] [ u ] dp[state][u] dp[state][u]表示已经访问过了 s t a t e state state中的节点,现在在 u u u点,访问剩下所有的节点,最后到0所需要的代价
显然转移方程 d p [ s t a t e ] [ v ] = min ⁡ ( d p [ s t a t e ∪ { u } ] [ u ] + d i s t [ v ] [ u ] ∣ u ∉ s t a t e ) dp[state][v]=\min\left(dp[state\cup\left\{u\right\}][u]+dist[v][u]|u\notin state\right) dp[state][v]=min(dp[state{u}][u]+dist[v][u]u/state)

简单来说就是把dfs改成递推的形式

#include<cstdio>
#include<cstring>
const int N = 15, INF = 0x3f3f3f3f;
//dp[state][u]访问过state中所有的节点,现在在u,访问剩下所有的节点,最后到0所需要的代价
int dp[1 << N][N], dist[N][N], n;
int tsp() {
	dp[(1 << n) - 1][0] = 0;
	for (int state = (1 << n) - 2; state >= 1; --state) {
		for (int v = 1; v < n; ++v) {
			if (0 == ((state >> v) & 1))continue;//v not in state
			for (int u = 0; u < n; ++u) {
				if (0 == ((state >> u) & 1)) {//u not in state
					int temp = dp[state | (1 << u)][u] + dist[v][u];
					if (temp < dp[state][v]) {
						dp[state][v] = temp;
					}
				}
			}
		}
	}
	for (int u = 1; u < n; ++u) {
		int temp = dp[1 << u][u] + dist[0][u];
		if (temp < dp[0][0]) {
			dp[0][0] = temp;
		}
	}
	if (dp[0][0] == INF)return -1;
	return dp[0][0];
}
int main() {
	int e;
	scanf("%d%d", &n, &e);
	memset(dist, INF, sizeof(dist));
	memset(dp, INF, sizeof(dp));
	while (e--) {
		int s, t, d;
		scanf("%d%d%d", &s, &t, &d);
		dist[s][t] = d;
	}
	printf("%d\n", tsp());
	return 0;
}

另一种写法

#include<cstdio>
#include<cstring>
const int N = 15, INF = 0x3f3f3f3f;
//dp[state][u]访问过state中所有的节点,现在在u,访问剩下所有的节点,最后到0所需要的代价
int dp[1 << N][N], dist[N][N], n;
int tsp() {
	dp[(1 << n) - 1][0] = 0;
	for (int state = (1 << n) - 2; state >= 0; --state) {
		for (int v = 0; v < n; ++v) {
			//if (0 == ((state >> v) & 1))continue;//v not in state
			for (int u = 0; u < n; ++u) {
				if (0 == ((state >> u) & 1)) {//u not in state
					int temp = dp[state | (1 << u)][u] + dist[v][u];
					if (temp < dp[state][v]) {
						dp[state][v] = temp;
					}
				}
			}
		}
	}
	if (dp[0][0] == INF)return -1;
	return dp[0][0];
}
int main() {
	int e;
	scanf("%d%d", &n, &e);
	memset(dist, INF, sizeof(dist));
	memset(dp, INF, sizeof(dp));
	//for (int i = 0; i < n; ++i) {
	//	dist[i][i] = 0;
	//}
	while (e--) {
		int s, t, d;
		scanf("%d%d%d", &s, &t, &d);
		dist[s][t] = d;
	}
	printf("%d\n", tsp());
	return 0;
}

正序

s t a t e state state是一个 b i t b o a r d bitboard bitboard,比如 0011 0011 0011表示访问过第 1 , 2 1,2 1,2个节点(注意这里0是不在state里的)
d p [ s t a t e ] [ u ] dp[state][u] dp[state][u]访问 s t a t e state state中所有的节点,且现在在u,所需要的代价
显然转移方程 d p [ s t a t e ] [ v ] = min ⁡ ( d p [ s t a t e \ { v } ] [ u ] + d i s t [ u ] [ v ] ∣ u ∈ s t a t e ) ( v ∈ s t a t e ) dp[state][v]=\min\left(dp[state\backslash\left\{v\right\}][u]+dist[u][v]|u\in state\right)(v\in state) dp[state][v]=min(dp[state\{v}][u]+dist[u][v]ustate)(vstate)

#include<cstdio>
#include<cstring>
const int N = 15, INF = 0x3f3f3f3f;
//dp[state][u]访问state中所有的节点,且现在在u,所需要的代价
int dp[1 << N][N], dist[N][N], n;
int tsp() {
	for (int state = 1; state < (1 << (n - 1)); ++state) {
		for (int v = 1; v < n; ++v) {
			if (0 == ((state >> (v - 1)) & 1))continue;//v not in state
			if ((1 << (v - 1)) == state) {//0->v
				dp[state][v] = dist[0][v];
			}
			else {
				dp[state][v] = INF;
				for (int u = 1; u < n; ++u) {
					if (0 == ((state >> (u - 1)) & 1))continue;//u not in state
					int temp = dp[state ^ (1 << (v - 1))][u] + dist[u][v];
					if (temp < dp[state][v]) {
						dp[state][v] = temp;
					}
				}
			}
		}
	}
	int ans = INF;
	for (int u = 1; u < n; ++u) {
		int temp = dp[(1 << (n - 1)) - 1][u] + dist[u][0];
		if (temp < ans) {
			ans = temp;
		}
	}
	if (INF == ans) {
		return -1;
	}
	return ans;
}
int main() {
	int e;
	scanf("%d%d", &n, &e);
	memset(dist, INF, sizeof(dist));
	while (e--) {
		int s, t, d;
		scanf("%d%d%d", &s, &t, &d);
		dist[s][t] = d;
	}
	printf("%d\n", tsp());
	return 0;
}

https://mp.weixin.qq.com/s?__biz=MzA4NzkxNzM3Nw==&mid=2457480484&idx=1&sn=bf45afaa2bd987747c34a03b9176e89f&chksm=87bc9b0ab0cb121c311299dbf16a55fe76b2b60d6d9e073f37deec49e28766ca416860a7659c&scene=21#wechat_redirect
https://blog.csdn.net/Code92007/article/details/86422273

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Nightmare004

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值