标签:方法 还需要 题解 传递 gis 路径 机器 初始 lang
首先,一定需要传递的是当前过程中遍历了多少点。
其次,我们还需要传递当前节点处已用了多少时间。
最后,还有我们走到当前节点遍历了哪些节点。
这让我想到了洛谷的 P1006 ,为了解决它我们把状态设计成了四维(当然也可以三维,甚至二维。甚至可以用网络流.。),两个人的位置都准确记录了。
但是仔细考虑一下,不难发现上述设计的状态很难在规定的空间(\(256 MB\))内完成 \(DP\) 数组的定义,或是干脆设计不出来,所以我们只能另辟蹊径,从另一个角度来设计状态。
回到我们的题目大意:
求从点 \(1\) 出发的两条路径 \(d_1,d_2\),使得 \({d_1}\cup{d_2} = U\)。
就可以发现其是两个人什么是无所谓的,我们主要求的是两条路径。
于是求一下所有路径,然后选两条 \(s_1,s_2\),使得 \({s_1}\cup{s_2} = U\) 。
求路径,且并不限制对于点的重复遍历,因此我们对原来的图是什么样的并不在意,我们可以先做一次 \(Floyd\) 的求出全源最短路来求路径。
先估一下时间复杂度是 \(\Theta({n^2}{2^n}+{n^3})\) ,空间复杂度 \(O({n2^n}+{n^2})\) ,可以过。
这个方程别看吓人,其实并不难,他本质就是由基础状态向其他状态扩散的过程。
值得注意的是,我们所得到的路径并不是最短路径,所以要单开一个数组(\(Path\))记录路径。
设初始状态 \(dp_{1,1}\) 为 \(0\) ,其余状态为 \(0\) 。
for(int i = 1 ; i < TOT; ++i)
for(int j = 1 ; j <= n ; ++j)
if(i & (1 << (j-1)))//可以从i点转移。
{
for(int k = 1; k <= n ; ++k)
//if(G[j][k] <= 0x3f3f3f3f && !(i&(1<<k-1)))
dp[i|(1<<(k-1))][k] = Min(dp[i|(1<<(k-1))][k],dp[i][j] + G[j][k]);
Path[i] = Min(Path[i],dp[i][j]);
}
如何求的最短路,其实也不难,我们可以通过类似 \(Floyd\) 的方法求出真正的最短路。
for(reg int k = 1; k < TOT; ++k)
for(reg int i = 1; i <= n ; ++i)
Path[k] = Min(Path[k],Path[k|(1<<(i-1))]);
最后,再统计一下答案。
for(reg int i = 1; i < TOT; ++i)
ans = Min(ans,Max(Path[i],Path[(1<<n)-1-i]));
# include <cstdio>
# include <cstring>
# define N 18
# define reg register
# define INF 0x3f3f3f3f
inline int Read()
{
int x = 0;char ch = getchar();
while(ch < ‘0‘ || ch > ‘9‘) ch = getchar();
while(ch >= ‘0‘ && ch <= ‘9‘){x = x*10 + (ch^48);ch = getchar();}
return x;
}
const int M = (1 << N);
inline int ABS(const int A){return A < 0 ? -A : A;}
inline int Min(const int a,const int b){return a < b ? a : b;}
inline int Max(const int a,const int b){return a > b ? a : b;}
int n,m,G[N + 42][N + 42],dp[M + 42][20],Path[M + 42],ans = 0x3f3f3f3f,TOT;
int main()
{
n = Read();m = Read();
memset(dp,0x3f,sizeof(dp));
memset(G,0x3f,sizeof(G));
memset(Path,0x3f,sizeof(Path));
dp[1][1] = 0;//初始化。
TOT = 1<<n;
for(reg int i = 1,x,y; i <= m ; ++i)
{
scanf("%d%d",&x,&y);
G[x][y] = G[y][x] = Read();
}
for(reg int k = 1; k <= n ; ++k)
for(reg int x = 1; x <= n ; ++x)
for(reg int y = 1; y <= n ; ++y)
G[x][y] = Min(G[x][y],G[x][k] + G[k][y]);
for(int i = 1 ; i < TOT; ++i)
for(int j = 1 ; j <= n ; ++j)
if(i & (1 << (j-1)))//可以从i点转移。
{
for(int k = 1; k <= n ; ++k)
//if(G[j][k] <= 0x3f3f3f3f && !(i&(1<<k-1)))
dp[i|(1<<(k-1))][k] = Min(dp[i|(1<<(k-1))][k],dp[i][j] + G[j][k]);
Path[i] = Min(Path[i],dp[i][j]);
}
for(reg int k = 1; k < TOT; ++k)
for(reg int i = 1; i <= n ; ++i)
Path[k] = Min(Path[k],Path[k|(1<<(i-1))]);
for(reg int i = 1; i < TOT; ++i)
ans = Min(ans,Max(Path[i],Path[(1<<n)-1-i]));
printf("%d",ans);
return 0;
}
其实这道题除了路径哪里的转换以外,其余的就是一道标准状压模板(~~但是我死在了路径上~~)。
标签:方法 还需要 题解 传递 gis 路径 机器 初始 lang
原文地址:https://www.cnblogs.com/2003-10-08/p/13323727.html