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 */
相关文章推荐
- Hibernate 缓存机制
- 046.@try 处理异常
- 047.@try…@catch... 捕捉异常
- zoj1071 Follow My Logic(没看题,不过据说很恶心,待ac)
- Java IO学习【13】利用字节流复制文件的4种方法详解
- pre标签
- 引用类型
- Skype for Business Server 2015系列(三)部署前端服务器-2
- 微机原理 之“极品飞车”课程设计
- ZOJ 3209 Treasure Map
- 数据库前缀索引
- 错误“Unexpected namespace prefix "xmlns" found for tag LinearLayout”的解决方法
- JAVA之父子类的构造函数、静态代码块等执行顺序
- scala中的控制语句
- 微机原理实验 lab8000 键盘数码管显示测试
- CSS作业及答案
- Zabbix之action配置
- UIView 和其子类 UILabel 的基本方法
- 小白学开发(iOS)OC_成员变量的作用域(2015-07-27)
- 描写生活美好的句子大全