您的位置:首页 > 其它

poj3613Cow Relays (经过n条边的最短路)

2015-07-27 22:29 176 查看
//poj 3613
//求经过n条边的最短路
//此题让我更深入的了解了最短路的floyed算法
//首先对于一个图的可达矩阵A而言(可达为1,不可达为0),A表示<i,j>是否直接可达。
//A*A表示<i,j>是否中间经过一个点k可达(因为是累加所有情况,只要有一个k可达,数字大于1,即为可达)。
//那么我们求的这个数字除了表示是否可达,有没有别的含义呢?
//在矩阵乘法过程中,我们做的累加实际上就是加法原理的累加,我们累加的结果是<i,j>的路径条数。
//对于<i,k>和<k,j>而言,假设<i,k>的路径条数为Aik,由于k-j是确定的,那么如果经过k到j就有Aik种可能性。那么是否可以经过k呢?取决于k-j是否有路,也就是Akj是否大于0.
//所以做了几次矩阵乘法,就相当于插入了几个点。

//回到本问题
//如果事先定义最短路只有经过边才成立的话
//在邻接矩阵中dis[i][i]=INF;
//floyed的过程实际上是类似于矩阵乘法的,只不过加了个限制条件。(dis[i][j]=dis[i][k]+dis[k][j])
//我们既然可以用矩阵乘法模拟插入点的过程计算经过x条边的了路径条数,
//那么也可以用floyed乘法来模拟入点的过程计算经过x条边的了最短路径长度,
//一次floyed后所求的矩阵就是在i,j中插入一个点的k的最短路。
//用当前矩阵再进行floyed即,再向<i,j>中插入点k',此时<i,j>中有两个点k,k'.在i,j中插入两个点的最短路。
//以前学的floyed更新最短路,虽然思想上是插入一个点,但是因为每次都只用dis一个数组,实际上更新过的点都会再次更新。
//我们每次都用新的数组,保留以前的数组,只用以前的数组进行更新,那么就可以保证,每次只用一点来更新<i,j>
//需要注意的是,我们进行的第一次floyed实际上是与自身进行的。初始化ans[i][i]=0;保证每次只并入端点。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
const int N=300;
const int INF=0x3fffffff;
#define clr(a) memset(a,0,sizeof(a))
int map

,temp

,ans

;
int used[10*N];
int p[10*N];
//c为待更新数组,初始化为INF,b为<i,j>中插了x个点的距离,a为<i,j>中插了y个点的距离
//正是由于c是一个完全新的数组,所以我们更新的时候可以看成一个新图
//每次插入一个点进行更新。b代表<i,k>间有x个点,且不管这x个点是怎么走的,可以重复走。
//a代表从<k,j>有y个点,是一个不断向外合并的过程。
void floyed(int a[]
,int b[]
,int c[]
,int cnt){
for(int k=1;k<=cnt;k++){
for(int i=1;i<=cnt;i++){
for(int j=1;j<=cnt;j++){
if(a[i][k]+b[k][j]<c[i][j])
c[i][j]=a[i][k]+b[k][j];
}
}
}
}

void copy(int n,int a[]
,int b[]
){
for(int i=0;i<=n;i++)
for(int j=0;j<=n;j++)
a[i][j]=b[i][j],b[i][j]=INF;
}
int solve(int s,int t,int n,int cnt){

while(n){
if(n&1){
floyed(ans,map,temp,cnt);
copy(cnt,ans,temp);
}
floyed(map,map,temp,cnt);
copy(cnt,map,temp);
n>>=1;
}
return ans[s][t];
}
int main(){
int n,t,S,E;
clr(used);
scanf("%d%d%d%d",&n,&t,&S,&E);
int u,v,w;
int cnt=0;
for(int i=0;i<=250;i++){
for(int j=0;j<=250;j++){
ans[i][j]=temp[i][j]=map[i][j]=INF;
}
ans[i][i]=0;
}
for(int i=0;i<t;i++){
scanf("%d%d%d",&w,&u,&v);
if(!used[u]){
used[u]=1;
p[u]=++cnt;
}
if(!used[v]){
used[v]=1;
p[v]=++cnt;
}
map[p[u]][p[v]]=map[p[v]][p[u]]=w;
}
printf("%d\n",solve(p[S],p[E],n,cnt));
return 0;
}
/*
5 6 1 5
1 2 1
1 5 3
2 3 2
2 5 2
3 4 1
4 5 2
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: