最短路专题

 

HDU 2544 最短路 http://acm.hdu.edu.cn/showproblem.php?pid=2544

题意:计算从1到n的最短时间。

最短路模板题。。。

 

Source Code:

(Dijkstra):

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

const int inf=0x3f3f3f3f;
const int nv=102;
int map[nv][nv];
int dis[nv];
bool s[nv];
int n,m;

int dijkstra(int src,int n){
    int i,j,u,tmp;
    for(int i=1;i<=n;i++){
        dis[i]=map[src][i];
        s[i]=false;
    }
    s[src]=true;
    dis[src]=0;
    for(i=1;i<n;i++){
        tmp=inf;
        for(j=1;j<=n;j++){
            if(!s[j]&&dis[j]<tmp){
                tmp=dis[j];
                u=j;
            }
        }
        s[u]=true;
        for(j=1;j<=n;j++){
            if(!s[j]&&map[u][j]+dis[u]<dis[j])
                dis[j]=map[u][j]+dis[u];
        }
    }
    return dis[n];
}

int main()
{
    while(~scanf("%d %d",&n,&m),n||m){
       memset(map,inf,sizeof(map));
       while(m--){
            int u,v,w;
            scanf("%d %d %d",&u,&v,&w);
            if(map[u][v]>w) map[u][v]=map[v][u]=w;
       }
       printf("%d\n",dijkstra(1,n));
    }
    return 0;
}


 

(Bellman Ford):

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

const int inf=0x3f3f3f3f;
const int nv=105;
struct Edge{
    int u,v,w;
}gra[nv*nv];
int dis[nv];

void BellmanFord(int n,int m){
    memset(dis,inf,sizeof(dis));
    dis[1]=0;
    for(int i=1;i<n;i++){
        for(int j=1;j<=m;j++){
            if(dis[gra[j].u]+gra[j].w<dis[gra[j].v]) dis[gra[j].v]=dis[gra[j].u]+gra[j].w;
            if(dis[gra[j].v]+gra[j].w<dis[gra[j].u]) dis[gra[j].u]=dis[gra[j].v]+gra[j].w;
        }
    }
}

int main()
{
    int n,m;
    while(scanf("%d %d",&n,&m),n+m){
        for(int i=1;i<=m;i++){
            int u,v,w;
            scanf("%d %d %d",&u,&v,&w);
            gra[i].u=u,gra[i].v=v,gra[i].w=w;
        }
        BellmanFord(n,m);
        printf("%d\n",dis[n]);
    }
    return 0;
}


(spfa):

#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;

const int maxn=105;
const int INF=0x3f3f3f3f;

int n,m;
int map[maxn][maxn],dis[maxn];
bool mark[maxn];

int Spfa(int src,int des){
    for(int i=0;i<=n;i++){
        mark[i]=false;
        dis[i]=INF;
    }
    queue<int>Q;
    mark[src]=true;
    dis[src]=0;
    Q.push(src);
    while(!Q.empty()){
        int first=Q.front();
        Q.pop();
        mark[first]=false;
        for(int i=1;i<=n;i++){
            if(dis[first]+map[first][i]<dis[i]){
                if(!mark[i]){
                    Q.push(i);
                    mark[i]=true;
                }
                dis[i]=dis[first]+map[first][i];
            }
        }
    }
    return dis[des];
}

int main()
{

    while(scanf("%d %d",&n,&m),n+m){
        int a,b,c;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++)
                map[i][j]=INF;
        }
        while(m--){
            scanf("%d %d %d",&a,&b,&c);
            if(map[a][b]>c) map[a][b]=map[b][a]=c;
        }
        printf("%d\n",Spfa(1,n));
    }
    return 0;
}


 

 

 

 

HDU 1548 A strange lift  http://acm.hdu.edu.cn/showproblem.php?pid=1548

题意:一幢N层的楼,每层有一个按钮,可以上或者下X层(当然不能跑到地下或超过楼的层数),问从A层到B层最少按几次按钮。

题解:在纸上画一下很容易想到是单源最短路。由于数据规模很小用BFS亦可。

 

Source Code:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

const int inf=0x3f3f3f3f;
const int maxn=205;
int Map[maxn][maxn],dis[maxn];
bool s[maxn];
int n,a,b;

bool OK(int x){
    if(x>0&&x<=n) return true;
    return false;
}

int dijkstra(int Src,int End){
    int i,j,u,tmp;
    for(i=1;i<=n;i++){
        dis[i]=Map[Src][i];
        s[i]=false;
    }
    s[Src]=true;
    dis[Src]=0;
    for(i=1;i<n;i++){
        tmp=inf;
        for(j=1;j<=n;j++){
            if(!s[j]&&dis[j]<tmp){
                tmp=dis[j];
                u=j;
            }
        }
        s[u]=true;
        for(j=1;j<=n;j++){
            if(dis[j]>dis[u]+Map[u][j])
                dis[j]=dis[u]+Map[u][j];
        }
    }
    return dis[End]>=inf?-1:dis[End];
}
int main()
{
    while(scanf("%d",&n),n){
        scanf("%d %d",&a,&b);
        memset(Map,inf,sizeof(Map));
        int x;
        for(int i=1;i<=n;i++){
            scanf("%d",&x);
            if(OK(i+x)) Map[i][i+x]=1;
            if(OK(i-x)) Map[i][i-x]=1;
        }
        if(a==b){
            printf("0\n");
            continue;
        }
        if(!OK(a)||!OK(b)){
            printf("-1\n");
            continue;
        }
        printf("%d\n",dijkstra(a,b));
    }
    return 0;
}


 HDU 2066  一个人的旅行 http://acm.hdu.edu.cn/showproblem.php?pid=2066

题意:一个人想去D个地方,可以从T个地方出发,问到达某个想去的地方的最短时间。

题解:多源最短路,但用Folyd会超时,可以对每个出发点进行单源最短路求法(Dijkstra)。

 

Source Code:

 

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

const int inf=0x3f3f3f3f;
const int maxn=1005;
int Map[maxn][maxn],dis[maxn];
int T,S,D,maxC;
bool mark[maxn];
int start[maxn],want[maxn];

void dijkstra(int src){
    int i,j,u,tmp;
    for(i=1;i<=maxC;i++){
        dis[i]=Map[src][i];
        mark[i]=false;
    }
    dis[src]=0;
    mark[src]=true;
    for(i=1;i<maxC;i++){
        tmp=inf;
        for(j=1;j<=maxC;j++){
            if(!mark[j]&&dis[j]<tmp){
                u=j;
                tmp=dis[j];
            }
        }
        mark[u]=true;
        for(j=1;j<=maxC;j++){
            if(!mark[j]&&dis[j]>dis[u]+Map[u][j])
                dis[j]=dis[u]+Map[u][j];
        }
    }
}

int main()
{
    //freopen("D:\in.txt","r",stdin);
    while(scanf("%d %d %d",&T,&S,&D)==3){
        memset(Map,inf,sizeof(Map));
        maxC=0;
        int a,b,t,ans=inf;
        for(int i=1;i<=T;i++){
            scanf("%d %d %d",&a,&b,&t);
            if(Map[a][b]>t) Map[a][b]=Map[b][a]=t;
            if(a>maxC) maxC=a;
            if(b>maxC) maxC=b;
        }
        for(int i=1;i<=S;i++)
            scanf("%d",&start[i]);
        for(int i=1;i<=D;i++)
            scanf("%d",&want[i]);
        for(int i=1;i<=S;i++){
            dijkstra(start[i]);
            for(int j=1;j<=D;j++)
                if(dis[want[j]]<ans) ans=dis[want[j]];
        }
        printf("%d\n",ans);
    }
    return 0;
}


HDU 2112 HDU Today http://acm.hdu.edu.cn/showproblem.php?pid=2112

题意:求从出发地start到目的地end的最短距离。

分析:用C++ STL中的map将字符串转换成整数,就是典型的最短路了。

 

Source Code:

#include <iostream>
#include <stdio.h>
#include <memory.h>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
using namespace std;

const int N = 155;
const int INF = 99999999;

map<string, int> mp;
map<string, bool> bp;
int way[N][N], dist[N];
bool visit[N];
string begin, end;
int n, ans;

void init()     //初始化函数
{
    int i, j;
    mp.clear(); //清空映射mp
    bp.clear(); //清空映射bp
    for(i = 0; i < N; i++)
        for(j = 0; j < N; j++)
            if(i == j) way[i][j] = 0;
            else way[i][j] = INF;
}

void input()    //输入函数
{
    int i, cost;
    ans = 1;
    string str1, str2;
    cin >> begin >> end;
    mp[begin] = 1;      //mp映射该string为1
    bp[begin] = true;   //bp映射该string为true
    if(!bp[end])
    {
        mp[end] = ++ans;
        bp[end] = true;
    }
    for(i = 1; i <= n; i++)
    {
        cin >> str1 >> str2 >> cost;
        if(!bp[str1])
        {
            mp[str1] = ++ans;
            bp[str1] = true;
        }
        if(!bp[str2])
        {
            mp[str2] = ++ans;
            bp[str2] = true;
        }
        way[mp[str1]][mp[str2]] = way[mp[str2]][mp[str1]] = cost;
    }
}

void spfa()
{
    int i, now;
    memset(visit, false, sizeof(visit));
    for(i = 0; i <= ans; i++) dist[i] = INF;
    dist[1] = 0;
    queue<int> Q;
    Q.push(1);
    visit[1] = true;
    while(!Q.empty())
    {
        now = Q.front();
        Q.pop();
        visit[now] = false;
        for(i = 1; i <= ans; i++)
        {
            if(dist[i] > dist[now] + way[now][i])
            {
                dist[i] = dist[now] + way[now][i];
                if(visit[i] == false)
                {
                    Q.push(i);
                    visit[i] = true;
                }
            }
        }
    }
}

int main()
{
    while(scanf("%d", &n))
    {
        if(n == -1) break;
        init();
        input();
        spfa();
        if(dist[mp[end]] != INF) printf("%d\n", dist[mp[end]]);
        else printf("-1\n");
    }
    return 0;
}


 

HDU 1217 Arbitrage http://acm.hdu.edu.cn/showproblem.php?pid=1217

题意:给出几种货币及货币间的汇率,问某种货币是否可以经过兑换其他的货币实现套利(就是兑换了一圈比原来的多)。

分析:多源最短路,结合C++ STL map和Folyd稍作变化即可。

 

Source Code:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cstdio>
#include <queue>
#include <map>
using namespace std;

const double inf=0x3f3f3f3f;
const int maxn=50;
map<string,int>mp;
map<string,bool>bp;
bool visit[maxn];
double way[maxn][maxn],dis[maxn];
int n,m,cas=0;
double len;

bool Floyd(){
    for(int k=1;k<=n;k++){
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                if(way[i][j]<way[i][k]*way[k][j])
                    way[i][j]=way[i][k]*way[k][j];
            }
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(way[i][i]>1)
                return true;
        }
    }
    return false;
}
int main()
{
    //freopen("D:\in.txt","r",stdin);
    while(scanf("%d",&n),n){
        string str,str1,str2;
        for(int i=1;i<=n;i++){
            cin>>str;
            mp[str]=i;
        }
        scanf("%d",&m);
        memset(way,0,sizeof(way));
        for(int i=1;i<=m;i++){
            cin>>str1>>len>>str2;
            way[mp[str1]][mp[str2]]=len;
        }
        if(Floyd()) printf("Case %d: Yes\n",++cas);
        else        printf("Case %d: No\n",++cas);
    }
    return 0;
}


 

 HDU 1535 Invitation Cards http://acm.hdu.edu.cn/showproblem.php?pid=1535

题意:有P个站点q条路线,且两个站点之间是单向的。求从1号站点到其他站点的最短路只和+从其他站点回到1号站点的最短路之和。

分析:去的时候求1到其他站点的单源最短路之和即可。对于回来的,是求其他所有站点到1号站点的最短路之和,很自然可以想到将图反向重建,再求1号站点到其他站点的单源最短路即可。

 

Source Code:

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int N=1000001;
const int INF=0x3f3f3f3f;
struct node{
    int v,w,next;
}edgego[N],edgeback[N];
int headgo[N],headback[N],dist[N];
bool mark[N];
int p,q;
void spfa(node edge[],int head[])
{
    memset(mark,false,sizeof(mark));
    for(int i=2;i<=p;i++)
        dist[i]=INF;
    dist[1]=0;
    queue<int>Q;
    Q.push(1);
    while(!Q.empty()){
        int x=Q.front();
        Q.pop();
        mark[x]=false;
        for(int e=head[x];e!=-1;e=edge[e].next){
            if(dist[edge[e].v]>dist[x]+edge[e].w){
                dist[edge[e].v]=dist[x]+edge[e].w;
                if(!mark[edge[e].v]){
                    mark[edge[e].v]=true;
                    Q.push(edge[e].v);
                }
            }
        }
    }
}
int main()
{
    int t,ans,u,v,w;scanf("%d",&t);
    while(t--){
        ans=0;
        scanf("%d %d",&p,&q);
        memset(headgo,-1,sizeof(int)*(p+1));
        memset(headback,-1,sizeof(int)*(p+1));
        for(int i=1;i<=q;i++){
            scanf("%d %d %d",&u,&v,&w);
            edgego[i].v=v;
            edgego[i].w=w;
            edgego[i].next=headgo[u];
            headgo[u]=i;

            edgeback[i].v=u;
            edgeback[i].w=w;
            edgeback[i].next=headback[v];
            headback[v]=i;
        }
        spfa(edgego,headgo);
        for(int j=2;j<=p;j++)
            ans+=dist[j];
        spfa(edgeback,headback);
        for(int l=2;l<=p;l++)
            ans+=dist[l];
        printf("%d\n",ans);
    }
    return 0;
}


 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值