hdu 1874 畅通工程续-spfa

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define M 100000
#define MAX 0x3f3f3f
using namespace std;


struct Edge
{
int from,to,val,next;
};
Edge edge[MAX];


queue<int> q;
int head[220];
int dist[220];
int vis[220];
int n,m;
int edgenum;


void addedge(int u,int v,int w)
{
Edge E={u,v,w,head[u]};//这个定义是可以的,从别人那里借鉴来的 
edge[edgenum]=E;
head[u]=edgenum++;
//printf("%d\n",edge[edgenum-1].next);
//printf("%d\n",head[u]);
//return 0;
}


void spfa(int s,int t)
{
//printf("%d\n",M);
//printf("%d\n",dist[2]);
int u,v;
int i;
dist[s]=0;
q.push(s);
vis[s]=1;
while(!q.empty())
{
u=q.front();
q.pop();
vis[u]=0;//每次出队列之后要把此点标记为未访问 
for(i=head[u];i!=-1;i=edge[i].next)
{
//printf("%d\n",i);
v=edge[i].to;
if(dist[v]>dist[u]+edge[i].val)
{
dist[v]=dist[u]+edge[i].val;
//printf("%d\n",dist[v]);
if(!vis[v])//注意要判断此点是否已在队列内
{
q.push(v);
vis[v]=1; //标记此点已在队列内 
}
}
}
}
if(dist[t]>=10000)
printf("-1\n");
else
printf("%d\n",dist[t]);
//return 0;
}


int main()
{
int i;
int a,b,c;
int s,t;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(head,-1,sizeof(head));


for(i=0;i<n;i++)
dist[i]=M;//用这个也不会费多少时间的 
/*
此处最好不要用
#define INF 0x3f3f3f3f 
memset(dist,INF,sizeof(dist));  
因为会超过int型的存储范围,可以试着输出dist[2]的值于INF的值进行比较,是不相等的
而且题目当中说X的取值范围不大于10000,所以可以定义一个100000来初始化dist[220]; 
*/

memset(vis,0,sizeof(vis));
edgenum=0;
for(i=0;i<m;i++)
{
scanf("%d%d%d",&a,&b,&c);


addedge(a,b,c);
addedge(b,a,c);
/*
这里为什么要这样输入就跟spfa的算法本身有关了,
举个例子:
数据是  3 1
       0 1 1
       1 2
这个是什么意思可以去看题目的 ,将这些数据带入程序进行模拟,那么我们可以知道
第一步:点1对点2进行更新 ,此时点2进入队列 
第二步:点2会对点1进行更新
差不多相当于map[1][2]=map[2][1],我们知道第一步是使用map[1][2],第二步是使用map[2][1]
所以在输入的时候要正反个输入一次 
不过我们此处用的是邻接表,输入之后的数据是这样的
0 1 1 edge[0]=E  edge[0].next=E.head[0]=-1  edgenum=1;   head[0]=0
1 0 1 edge[1]=E  edge[1].next=E.head[1]=-1  edgenum=2;   head[1]=1;
此处注意E.head[]跟head[]是不相等的 
正面和反面的输入的val值是不变的,所以在进行正反更新的时候是不会影响的,这个跟邻接表的性质有关
我觉得他们之间的连接与应用真的是太巧妙了 
*/

}
scanf("%d%d",&s,&t);
spfa(s,t);
}
return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值