题目名称:Til the Cows Come Home
题目链接:http://poj.org/problem?id=2387
题意:有N个点,T条边,问从1->N的最短路径
注意:INF不能设置太大,因为加法时可能溢出变负数,所以设为比最大值大一点就行,如10条最大1000的边则设置为10*1000+1(注意不是一条边的最大,是全部边和的最大)
思路:模板题,然后记得有重边
代码如下:只有dijkstra要判重边,spfa不用,,一般用spfa,负权可以用
dijkstra (O(n^2))
#include<cstdio>
#include<cstring>
#include<iostream>
#include<string>
#include<algorithm>
#include<map>
#include<vector>
#include<queue>
using namespace std;
const int maxn=1005;
const int INF=0x3f3f3f3f;
int dis[maxn][maxn]={INF};
int t,n;
int dijkstra()
{
int d[maxn];
bool vis[maxn]={false};
memset(d,INF,sizeof(d));
d[1]=0;
for(int i=1;i<=n;i++)
{
int x,m=INF;
for(int j=1;j<=n;j++)
{
if(!vis[j]&&d[j]<=m)
{
m=d[j];
x=j;
}
}
vis[x]=true;
for(int j=1;j<=n;j++)
{
d[j]=min(d[j],d[x]+dis[x][j]);
}
}
return d[n];
}
int main()
{
while(scanf("%d%d",&t,&n)!=EOF)
{
memset(dis,INF,sizeof(dis));
int from,to,dist;
for(int i=0;i<t;i++)
{
scanf("%d%d%d",&from,&to,&dist);
if(dist<dis[from][to]) //判重边
{
dis[from][to]=dist;
dis[to][from]=dist;
}
}
printf("%d\n",dijkstra());
}
return 0;
}
邻接矩阵vector版的spfa
#include<cstdio>
#include<string>
#include<queue>
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
const int maxn=1005;
const int INF=0x3f3f3f3f;
int dis[maxn][maxn]={INF}; //记录权值
bool inque[maxn]; //记录是否在队列中
int d[maxn]; //记录最短路
int t,n;
vector<int> vr[maxn];
void spfa(int s)
{
for(int i=1;i<=n;i++)
{
d[i]=INF;
inque[i]=false;
}
queue<int> Q;
d[s]=0;
inque[s]=true;
Q.push(s);
while(!Q.empty())
{
int x=Q.front();
Q.pop();
inque[x]=false;
for(int i=0;i<vr[x].size();i++)
{
int y=vr[x][i];
if(d[y]>d[x]+dis[x][y])
{
d[y]=d[x]+dis[x][y];
if(!inque[y])
{
inque[y]=true;
Q.push(y);
}
}
}
}
}
int main()
{
while(scanf("%d%d",&t,&n)!=EOF)
{
memset(dis,INF,sizeof(dis));
int from,to,dist;
for(int i=0;i<t;i++)
{
scanf("%d%d%d",&from,&to,&dist);
if(dist<dis[from][to])
{
dis[from][to]=dist;
dis[to][from]=dist;
}
vr[from].push_back(to);
vr[to].push_back(from);
}
spfa(1);
printf("%d\n",d[n]);
}
return 0;
}
邻接表的spfa
#include<cstdio>
#include<string>
#include<queue>
#include<iostream>
#include<cstring>
using namespace std;
const int maxn=2005;
const int INF=0x3f3f3f3f;
//int dis[maxn][maxn]={INF}; //记录权值
bool inque[maxn]; //记录是否在队列中
int d[maxn]; //记录最短路
int t,n;
int head[maxn];
struct Edge
{
int v,w,next; //v记录这一条边下个点,w记录该边的权值,next记录在这个点上的下一条边
}edge[maxn*2];
int cnt;
void add_edge(int u,int v,int w)
{
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].next=head[u];
head[u]=cnt++;
}
void init()
{
cnt=0;
memset(head,-1,sizeof(head));
memset(inque,false,sizeof(inque));
// memset(dis,INF,sizeof(dis));
memset(d,INF,sizeof(d));
}
void spfa(int s)
{
queue<int> Q;
d[s]=0;
Q.push(s);
inque[s]=true;
while(!Q.empty())
{
int u=Q.front();
Q.pop();
inque[u]=false;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
int w=edge[i].w;
if(d[v]>d[u]+w)
{
d[v]=d[u]+w;
if(!inque[v])
{
inque[v]=true;
Q.push(v);
}
}
}
}
}
int main()
{
while(scanf("%d%d",&t,&n)!=EOF)
{
int from,to,dist;
init();
for(int i=0;i<t;i++)
{
scanf("%d%d%d",&from,&to,&dist);
add_edge(from,to,dist);
add_edge(to,from,dist);
}
spfa(1);
printf("%d\n",d[n]);
}
return 0;
}
//这道题红果果的超时了。。
#include<cstdio>
#include<string>
#include<queue>
#include<iostream>
#include<cstring>
using namespace std;
const int maxn=1005;
const int INF=0x3f3f3f3f;
int d[maxn][maxn];
int n,t;
void floyd()
{
for(int k=1;k<=n;k++) //注意先k,i和j的顺序可以变
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}
int main()
{
while(scanf("%d%d",&t,&n)!=EOF)
{
int from,to,dist;
memset(d,INF,sizeof(d));
for(int i=1;i<=t;i++)
{
scanf("%d%d%d",&from,&to,&dist);
if(dist<d[from][to])
{
d[from][to]=dist;
d[to][from]=dist;
}
}
for(int i=1;i<=n;i++)
{
d[i][i]=0;
}
floyd();
printf("%d\n",d[1][n]);
}
return 0;
}