题意:从0走遍1~n最后再返回到0,一个点可以走多次,求经过的最短距离。
分析:由于一个点可以走多次,所以需要求出任意两点间的最短距离,就要用到floyd算法,同时接下来可以搜索做复杂度是O(n!),而状态压缩的时间效率就高了,关于DP自己有时候状态转移方程知道了,却不知道如何去实现,循环时哪层放在外面,哪层放在里面,所以很容易把DP写成了暴力的搜索,自己要多想想。
状态转移方程:dp[S][i] = min(dp[S^(1<<(i-1))][j] + dis[j][i],dp[S][i])
四不像的搜索:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <cctype>
#include <vector>
#include <set>
#include <map>
#include <queue>
using namespace std;
#define ll long long
const int maxn = (1<<10) + 5;
const int inf = 0x7f7f7f7f;
int g[15][15];
int n;
int mmin;
inline int getone(int x)
{
int res = 0;
while (x)
{
x &= (x-1);
res++;
}
return res;
}
void floyd()
{
for (int k = 0; k <= n; k++)
{
for (int i = 0; i <= n; i++)
{
for (int j = 0; j <= n; j++)
g[i][j] = min(g[i][j],g[i][k]+g[k][j]);
}
}
}
void dfs(int u, int state, int cur)//写搜索本可以不用二进制
{
if (getone(state)==0)
{
if (mmin > cur+g[u][0]) mmin = cur+g[u][0];
return;
}
for (int i = 1; i <= n; i++)
{
if (state&(1<<(i-1)) && g[u][i] != -1)
{
dfs(i, (1<<(i-1))^state, cur+g[u][i]);
}
}
}
int main()
{
//freopen("input.txt", "r", stdin);
while (cin >> n && n)
{
for (int i = 0; i <= n; i++)
for (int j = 0; j <= n; j++)cin >> g[i][j];
floyd();
mmin = inf;
for (int i = 1; i <=n; i++)
{
dfs(i, (1<<(i-1))^((1<<n)-1), g[0][i]);
}
cout << mmin << endl;
}
}
DP:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <cctype>
#include <vector>
#include <set>
#include <map>
#include <queue>
using namespace std;
#define ll long long
const int maxn = (1<<10) + 5;
const int inf = 0x7f7f7f7f;
int g[15][15];
int f[maxn][12];
int n;
int mmin;
void floyd()
{
for (int k = 0; k <= n; k++)
{
for (int i = 0; i <= n; i++)
{
for (int j = 0; j <= n; j++)
g[i][j] = min(g[i][j],g[i][k]+g[k][j]);
}
}
}
int main()
{
//freopen("input.txt", "r", stdin);
while (cin >> n && n)
{
for (int i = 0; i <= n; i++)
for (int j = 0; j <= n; j++)cin >> g[i][j];
floyd();
for (int s = 1; s < (1<<n); s++)//要先枚举状态,跟floyd有点像,此时i,j之间可以进行松弛操作
{
for (int i = 1; i <= n; i++)
{
if (s&(1<<(i-1)))
{
if (s == (1<<(i-1)))f[s][i] = g[0][i];
else
{
f[s][i] = inf;
for (int j = 1; j <= n; j++)
if (s&(1<<(j-1)) && i != j)
f[s][i] = min(f[s^(1<<(i-1))][j]+g[j][i], f[s][i]);
}
}
}
}
int ans = inf;
for (int i = 1; i <= n; i++)
if (ans > f[(1<<n)-1][i]+g[i][0]) ans = f[(1<<n)-1][i]+g[i][0];
cout << ans << endl;
}
}