做图论的都是上辈子折翼的天使。。。有点难想,但若有明确的思路,程序很好打
清除所有点的标号
设d[0]=0,其他d[i]=INF
循环n次
{
在所以未标号结点中,选出d值最小的节点x
标记节点x
对于从x出发的所有边(x,y), 更新d[y]=min(d[y],d[x]+w(x,y));
}
错了几次
第一次把路程和金钱分开处理了,很快查出来
第二次又错了,但心想这是模板题,怎么错了,一看discuss,重边。。哭了。。
打的时候发现了很多问题
假如INF==1<<31-1
memset(a,INF,sizeof(a)); 初始都为0.。。
而0x1f==31
memset(a,0x1f,sizeof(a))后,初始都为522133279.
memset(a,0x1f1f1f1f,sizeof(a))后,初始都为522133279.
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1010;
const int INF=0x1f1f1f1f;
int dislen[maxn];
int discost[maxn];
int w[maxn][maxn];
int ss[maxn][maxn];
bool visit[maxn];
int n,m;
int s,t;
int main()
{
while(scanf("%d",&n)!=EOF)
{
scanf("%d",&m);
if(n==0&&m==0)
break;
int i,j;
memset(visit,true,sizeof(visit));
memset(w,0x1f,sizeof(w));
memset(ss,0x1f,sizeof(ss));
int u,v,len,cost;
// for(i=1; i<=n; i++)
// {
// w[i][i]=0;
// ss[i][i]=0;
// }
for(i=1;i<n;i++)
{
for(j=1;j<=n;j++)
{
cout<<w[i][j]<<' ';
}
cout<<endl;
}
for(i=0; i<m; i++)
{
scanf("%d%d%d%d",&u,&v,&len,&cost);
if(w[u][v]>len||w[u][v]==len&&ss[u][v]>cost)
{
w[u][v]=len;
w[v][u]=len;
ss[u][v]=cost;
ss[v][u]=cost;
}
}
scanf("%d%d",&s,&t);
for(i=1; i<=n; i++)
{
if(i==s)
{
dislen[i]=0;
discost[i]=0;
}
else
{
dislen[i]=w[s][i];
discost[i]=ss[s][i];
}
}
for(j=1; j<=n; j++)
{
int x;
int minn=INF;
for(i=1; i<=n; i++)
{
if(visit[i]==true&&dislen[i]<minn)
{
minn=dislen[i];
x=i;
}
}
visit[x]=false;
for(i=1; i<=n; i++)
{
if(visit[i]==true&&dislen[i]>dislen[x]+w[x][i])
{
dislen[i]=dislen[x]+w[x][i];
discost[i]=discost[x]+ss[x][i];
}
else if(visit[i]==true&&dislen[i]==dislen[x]+w[x][i]&&ss[x][i]+discost[x]<discost[i])
{
discost[i]=discost[x]+ss[x][i];
}
}
}
printf("%d %d\n",dislen[t],discost[t]);
}
return 0;
}