poj2387

题目名称: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;
}

floyd 求每两点间的最短路 (O(n^3))
//这道题红果果的超时了。。
#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;
}


posted @ 2015-07-28 11:27  maplefighting  阅读(124)  评论(0编辑  收藏  举报