POJ 3613 Cow Rlays
题意:求s到t的经过m条边的最短路
设d[i,j](M)表示从i到j经过M条边的最短路(由于迭代倍增,M并不需要再用一维空间),a为读进的图,则:d[i,j](M)=Min(d[i,k](M-1)+a[k,j]) (1<=i,j,k<=n)矩阵乘法的形式:A[i,j]=∑(B[i,k]*C[k,j]),本题方程的形式:d[i,j]=Min(d[i,k]+a[k,j]),有很大的相似之处,因此只需要把矩阵乘法模板中的“∑”变为“Min”,“*”变为“+”,即可实现二者的相互转化。
具体实现方式如下:矩阵乘法当然要用到快速幂:把N用二进制表示,若N确当前位是1,则根据方程对矩阵d和a进行“Min”和“+”操纵(相当于两个矩阵相乘),得到的结果存在一个辅助空间b数组中,然后把b赋回给d。并且每次对a自身进行Min和+操纵(相当于自乘),同样利用一下b数组作辅助空间,每次完后N右移一位再进行下一次循环,直至N=0。小技巧:由于读进数据的点比较分散,可以对其进行离散化,降低时空复杂度,效果甚好。
#include<cstdio>
#include<cstring>
#include<fstream>
#define inf ((__int64)1<<31-1);
using namespace std;
__int64 g[205][205],ans[205][205],tmp[205][205];
int p[1005];
int pos=1,n;
void solve(int m)
{
int i,j,k;
while(m){
if(m%2){
for(i=1;i<=n;i++)for(j=1;j<=n;j++) tmp[i][j]=inf;
for(k=1;k<=n;k++)for(i=1;i<=n;i++)for(j=1;j<=n;j++)
if(tmp[i][j]>ans[i][k]+g[k][j])
tmp[i][j]=ans[i][k]+g[k][j];
for(i=1;i<=n;i++)for(j=1;j<=n;j++) ans[i][j]=tmp[i][j];
// for(i=1;i<=n;i++){for(j=1;j<=n;j++)printf("%12d,%2d:%I64d",i,j,ans[i][j]);printf("\n");}
}
for(i=1;i<=n;i++)for(j=1;j<=n;j++) tmp[i][j]=inf;
for(k=1;k<=n;k++)for(i=1;i<=n;i++)for(j=1;j<=n;j++)
if(tmp[i][j]>g[i][k]+g[k][j])
tmp[i][j]=g[i][k]+g[k][j];
for(i=1;i<=n;i++)for(j=1;j<=n;j++) g[i][j]=tmp[i][j];
//for(i=1;i<=n;i++){for(j=1;j<=n;j++)printf("%16d,%2d:%I64d",i,j,ans[i][j]);printf("\n");}
m/=2;
}
return ;
}
int main()
{
freopen("in","r",stdin);
freopen("out","w",stdout);
int E,V,s,t,u,v,w;
for(int i=0;i<=200;i++){
for(int j=0;j<=200;j++){g[i][j]=inf;ans[i][j]=inf;}
ans[i][i]=0;
}
scanf("%d%d%d%d",&m,&E,&s,&t);
while(E--){
scanf("%d%d%d",&w,&u,&v);
if(p[u]==0) p[u]=pos++;
if(p[v]==0) p[v]=pos++;
g[p[u]][p[v]]=g[p[v]][p[u]]=w;
}
n=--pos;
solve(m);
printf("%lld\n",ans[p[s]][p[t]]);
return 0;
}
感谢法师找到的机房,小爷也可以蹦跶好几天了啊0.0……