题意: 将所有外卖送去所有对应地点再回到店铺,求最短路。
分析:Floyed预处理任意两点最小距离,然后二维状压(最后的结束位置要考虑,不然回到起点的距离没办法计算)。
d
p
[
j
+
1
]
[
(
1
<
<
j
)
+
i
]
=
m
i
n
(
d
p
[
j
+
1
]
[
(
1
<
<
j
)
+
i
]
,
d
p
[
k
+
1
]
[
i
]
+
m
p
[
k
+
1
]
[
j
+
1
]
)
:
表
示
以
第
j
个
位
置
结
束
的
状
态
i
的
路
径
长
度
dp[j + 1][(1 << j) + i] = min(dp[j + 1][(1 << j) + i], dp[k + 1][i] + mp[k + 1][j + 1]):表示以第j个位置结束的状态i的路径长度
dp[j+1][(1<<j)+i]=min(dp[j+1][(1<<j)+i],dp[k+1][i]+mp[k+1][j+1]):表示以第j个位置结束的状态i的路径长度.
PS:这种题不难,注意开的维度,仔细检查状压时的下标。
状压写法:
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
#define met(s) memset(s, 0, sizeof(s))
#define rep(i, a, b) for(int i = a; i <= b; ++i)
template <class T> inline void scan_d(T &ret) {
char c; ret = 0;
while ((c = getchar()) < '0' || c > '9');
while (c >= '0' && c <= '9') {
ret = ret * 10 + (c - '0'), c = getchar();}}
typedef long long LL;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int INF = 0x3f3f3f3f;
const int mod = 1e8;
const int MAXN = 15;
int dp[MAXN][1 << 12];
int mp[MAXN][MAXN];
int n, m;
inline void floyed() {
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= n; ++j) {
for(int k = 1; k <= n; ++k) {
mp[j][k] = min(mp[j][k], mp[j][i] + mp[i][k]);
}
}
}
}
int main() {
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
while(scanf("%d", &n) && n) {
n += 1;
memset(dp, INF, sizeof(dp));
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= n; ++j) {
scanf("%d", &mp[i][j]);
}
}
floyed(); dp[1][1] = 0; int ans = INF;
//for(int i = 0; i < n; ++i) dp[1 << i] = mp[1][i + 1];
for(int i = 1; i < (1 << n); ++i) {
if(!(i & 1)) continue;
for(int j = 0; j < n; ++j) {
if((1 << j) & i) continue;
for(int k = 0; k < n; ++k) {
if(!((1 << k) & i)) continue;
dp[j + 1][(1 << j) + i] = min(dp[j + 1][(1 << j) + i], dp[k + 1][i] + mp[k + 1][j + 1]);
if((1 << n) - 1 == i + (1 << j)) {
ans = min(ans, dp[j + 1][(1 << n) - 1] + mp[j + 1][1]);
// printf("## %d %d\n", mp[k + 1][1], k + 1);
}
}
}
}
printf("%d\n", ans);
}
return 0;
}
n e x t next next_ p e r m u t a t i o n : permutation: permutation:
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
#define met(s) memset(s, 0, sizeof(s))
#define rep(i, a, b) for(int i = a; i <= b; ++i)
template <class T> inline void scan_d(T &ret) {
char c; ret = 0;
while ((c = getchar()) < '0' || c > '9');
while (c >= '0' && c <= '9') {
ret = ret * 10 + (c - '0'), c = getchar();}}
typedef long long LL;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int INF = 0x3f3f3f3f;
const int mod = 1e8;
const int MAXN = 15;
int a[15];
int mp[MAXN][MAXN];
int n, m;
inline void floyed() {
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= n; ++j) {
for(int k = 1; k <= n; ++k) {
mp[j][k] = min(mp[j][k], mp[j][i] + mp[i][k]);
}
}
}
}
int main() {
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
while(scanf("%d", &n) && n) {
n += 1;
for(int i = 1; i <= n; ++i) {
a[i] = i;
for(int j = 1; j <= n; ++j) {
scanf("%d", &mp[i][j]);
}
}
floyed(); int ans = INF;
do {
int sum = mp[a[n]][1] + mp[1][a[1]];
for(int i = 1; i < n; ++i) {
sum += mp[a[i]][a[i + 1]];
}
ans = min(sum, ans)
; }while(next_permutation(a + 2, a + n + 1));
printf("%d\n", ans);
}
return 0;
}