hdu1599
解题报告:
要通过此题就要明白
f
l
o
y
e
d
floyed
floyed 算法原理及其每步的含义。
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);
}
}
}
其本质就是动态规划
k作为阶段必须置于最外层,i,j作为附加状态置于内层
mp<k,i,j>可以理解为 经过若干个编号不超过k的节点从i到j的最短路,进而转化为两个子问题:
1.经过给若干个编号不超过k-1的节点从i到j最短路
2.节点i经过k节点到j节点
因此: mp<k,i,j> = min(mp<k-1,i,j>, mp<k-1,i,k> + mp<k-1,k,j>)
再通滚动数组优化得到 mp<i,j>
在枚举每次的ki时,我们就已经求出来 1~k-1之间的最短路。
回到本题求最小环:
假设存在一条最小环
u
−
v
−
k
−
u
u-v-k-u
u−v−k−u,既然是最小环,当拆掉
u
−
v
u-v
u−v时,
v
−
k
−
u
v-k-u
v−k−u就是
(
u
,
v
)
(u,v)
(u,v)最短路。
再回到前面floyed算法每次枚举
k
i
k_i
ki 的时候我们就已经求出来1~k-1之间的最短路,前
k
−
1
k-1
k−1 个的点不包含
k
k
k 节点且它们之间的最短路径之间也不经过
k
k
k 节点。
从前
k
−
1
k-1
k−1 个点中取两点
i
,
j
i,j
i,j ,
(
i
,
j
)
(i,j)
(i,j) 之间的最短路已经求得且不经过节点
k
k
k,再跟据floyed原理以k为中间节点进行更新得到最小环
i
−
j
−
k
−
i
i-j-k-i
i−j−k−i。
#include<bits/stdc++.h>
#define LL long long
#define pii pair<LL,int>
#define all(x) x.begin(),x.end()
#define wp(x) write(x),putchar('\n')
#define wpl(x) write(x),putchar(' ')
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn = 2e5 + 5;
inline int read() {
int s = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {s = (s << 1) + (s << 3) + ch - '0'; ch = getchar();}
return s * f;
}
inline void write(LL x) {
if (x < 0) putchar('-'), x = -x;
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
int mp[105][105],g[105][105];
int main(){
int n,m,u,v,w;
while(scanf("%d%d",&n,&m)!=EOF){
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) g[i][j]=mp[i][j]=(i==j)?0:1e8;
for(int i=1;i<=m;i++){
scanf("%d%d%d",&u,&v,&w);
g[u][v]=mp[u][v]=min(mp[u][v],w);
g[v][u]=mp[v][u]=min(mp[v][u],w);
}
int ans=1e8;
for(int k=1;k<=n;k++){
for(int i=1;i<k;i++){
for(int j=i+1;j<k;j++){
ans=min(ans,mp[i][j]+g[i][k]+g[k][j]);
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);
}
}
}
if(ans==1e8) printf("No solution.\n");
else printf("%d\n",ans);
}
return 0;
}