旅行商问题
91. 最短Hamilton路径
题意:旅行商问题,即从 \(1\) 走到 \(n\) 不重不漏,然后求最小距离。
题解:状态压缩dp,显然的是,要从某种状态到某种状态并且合法,然后取 \(min\),然后全部遍历。所以设 \(dp_{i, j}\) 的含义是,最后一个点是 \(i\) 点,然后走过了 \(j\) 这个 \(01\) 串的有 \(1\) 的点。然后要想的是顺序问题,那么我们必然是从上一个点推到 \(i\) 点,所以可以遍历所有点,然后得到 \(k\) 点,\(k\) 点一定是在这个 \(j\) 里面,然后那么 $$dp_{i, j} = MIN{dp_{i, j}, dp_{k, j - (1 >> i)}}$$。
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <map>
#include <cstring>
using namespace std;
typedef long long ll;
const int N = 21;
int dp[N][1 << N];
int w[N][N];
void solve() {
int n;cin >> n;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cin >> w[i][j];
}
}
memset(dp, 0x3f, sizeof dp);
dp[0][1] = 0;
for (int j = 0; j < 1 << n; j++) {
for (int i = 0; i < n; i++) {
if ((j >> i) & 1) {
for (int k = 0; k < n; k++) {
if (((j - (1<<i)) >> k) & 1 ) {
dp[i][j] = min(dp[i][j], dp[k][j - (1 << i)] + w[k][i]);
}
}
}
}
}
cout << dp[n - 1][(1 << n) - 1] << endl;
}
int main() {
int t = 1;//cin >> t;
while (t--) solve();
return 0;
}
E - Traveling Salesman among Aerial Cities
题意:旅行商问题裸题,只不过多出来一项操作是不重不漏走完,并且还要回到原点,也没啥,如果理解了旅行商问题的 \(dp\) 方程代表含义,就很简单。
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <map>
#include <cstring>
using namespace std;
typedef long long ll;
const ll N = 29;
struct node {
ll x, y, z;
}a[22];
bool check(ll j, ll k, ll n) {
for (ll i = 0; i < n; i++) {
if (j >> i & 1) {
for (ll ii = -1; ii <= 1; ii++) {
ll d= i + ii;
d = max((ll)0, d);
if ( k >> d & 1 ) {
return 0;
}
}
}
}
return 1;
}
ll w[N][N];
ll dp[N][1 << 18];
void solve() {
ll n;cin >> n;
for (ll i = 0; i < n; i++) cin >> a[i].x >> a[i].y >> a[i].z;
for (ll i = 0; i < n; i++) {
for (ll j = 0; j < n; j++)
{
if (i == j)continue;
w[i][j] = abs(a[i].x - a[j].x) + abs(a[i].y - a[j].y) + max((ll)0, a[j].z - a[i].z);
w[j][i] = abs(a[i].x - a[j].x) + abs(a[i].y - a[j].y) + max((ll)0, a[i].z - a[j].z);
}
}
memset(dp , 0x3f, sizeof dp);
dp[0][1] = 0;
for (ll j = 0; j < 1 << n; j++) {
for (ll i = 0; i < n; i++) {
for (ll k = 0; k < n; k++) {
if ( (j - (1 << i) ) >> k & 1 && (j - (1 << i) )>=0) {
dp[i][j] = min(dp[i][j], dp[k][j - (1 << i)] + w[k][i]);
}
}
}
}
ll ans = 0x7fffffff;
for (ll i = 1; i < n; i++) ans = min(ans, dp[i][ (1 << n) - 1] + w[i][0]);//多出来了这个,就是知道了dp数组含义后,就很简单
cout << ans << endl;
}
signed main() {
ll t = 1;//cin >> t;
while (t--) solve();
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步