最短路相关题目

1.luoguP1807 最长路_NOI导刊2010提高(07)

直通

思路:

  求最长路,其实跟最短路是一毛一样的,跑一边spfa就好。我们只需要加点小优化:在存边的时候把w存为-w,然后最后输出的时候输出-dis[n]就好

坑点:

  这是一个有向图,不是无向图

上代码:

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

const int N = 1501;
const int M = 50001;
int n,m;
struct node {
    int next,to,w;
} e[M<<1];
int top,head[N];
void add(int u,int v,int w) {
    top++;
    e[top].to=v;
    e[top].w=w;
    e[top].next=head[u];
    head[u]=top;
}

queue<int>q;
int dis[N];
bool flag,vis[N];
void spfa() {
    memset(dis,0x7f,sizeof(dis));
    q.push(1);
    vis[1]=true;
    dis[1]=0;
    while(!q.empty()) {
        int u=q.front();
        q.pop();
        vis[u]=false;
        for(int i=head[u],v,w; i; i=e[i].next) {
            v=e[i].to,w=e[i].w;
            if(dis[u]+w<dis[v]) {
                dis[v]=dis[u]+w;
                if(!vis[v]) {
                    vis[v]=true;
                    q.push(v);
                }
                if(v==n) flag=true;
            }
        }
    }
}

int main() {
    scanf("%d%d",&n,&m);
    for(int i=1,u,v,w; i<=m; i++) {
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,-w);
    }
    spfa();
    if(!flag) printf("-1");
    else printf("%d",-dis[n]);
    return 0;
}
View Code

2.P1119 灾后重建

直通

思路:

  出题人超良心的帮我们把询问按时间顺序排序了,那我们就不需要vis数组记录每个点是否已经做过Floyd,只要每次读入的时候把之前的时间没处理过的全部处理一遍就可以。

坑点:

  注意该题的初始化!其实要说的话应该是注意所有的Floyd的初始化,因为我们要用到dis[i][k]+dis[k][j],所以如果memset0x7f的话会有可能炸出负数来,那样的话Floyd就不准了,所以我们在进行初始化的时候最好是要初始化(memset)为0x3f才可以

上代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath> 
#define INF 0x3f3f3f3f
using namespace std;

const int M = 50015;
const int N = 233;
int n,m,Q,k;
int dis[N][N],t[M];

int main() {
    scanf("%d%d",&n,&m);
    memset(t,0x3f,sizeof(t));
    memset(dis,0x3f,sizeof(dis));
    for(int i=0; i<n; i++) scanf("%d",&t[i]),dis[i][i]=0;
    for(int i=1,u,v,w; i<=m; i++) {
        scanf("%d%d%d",&u,&v,&w);
        dis[u][v]=dis[v][u]=w;
    }
    scanf("%d",&Q);
    for(int x=1,u,v,c; x<=Q; x++) {
        scanf("%d%d%d",&u,&v,&c);
        //注意这里的k是不需要进行清零的,具体原因嘛,那就是因为良心的出题人啦 
        while(t[k]<=c) {
            for(int i=0; i<n; i++)
                for(int j=0; j<n; j++)
                    dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
            k++;
        }
        //宏定义的INF就等价于memset的数 
        //所以dis[u][v]==INF就说明两点之间并没有进行联通
        //而t[u]以及t[v] >c则是端点并没有建好的情况 
        if(dis[u][v]==INF || t[u]>c || t[v]>c) printf("-1\n");
        else printf("%d\n",dis[u][v]);
    }
    return 0;
}
View Code

 

posted @ 2017-11-04 21:23  夜雨声不烦  阅读(349)  评论(0编辑  收藏  举报