kuangbin带我飞 专题四 最短路

poj 2387 

全裸的最短路,随便什么算法都能过

Poj 2253

这题可以用最小生成树来做,kruskal搞一下,如果1-2连同,此时的边就是青蛙跳的最大距离

while(scanf("%d",&n)&&n){
        kase++;
        int xcount=0;
        for(int i=1;i<=n;i++) pre[i]=i;
        for(int i=1;i<=n;i++){
            scanf("%d%d",&a[i],&b[i]);
            for(int j=1;j<i;j++){
                p[xcount].from=j;
                p[xcount].to=i;
                p[xcount++].cost=sqrt(double((a[i]-a[j])*(a[i]-a[j])+(b[i]-b[j])*(b[i]-b[j])));
            }
        }
        sort(p,p+xcount,cmp);
        for(int i=0;i<xcount;i++){
            Union(p[i].from,p[i].to);
            if(Find(1)==Find(2)){
                printf("Scenario #%d\nFrog Distance = %.3lf\n\n",kase,p[i].cost);
                break;
            }
        }
    }

poj 1797

这个题是求1-n的路中,最小边最大的一条路,可以用spfa变化下求。

dis[k]=max(dis[k],min(dis[x],edge[x][k]));

void spfa(int u){
    queue<int> q;
    q.push(u);
    vis[u]=1;
    dis[u]=INF;
    while(!q.empty()){
        int x=q.front();
        q.pop();
        vis[x]=0;
        for(int i=0;i<v[x].size();i++){
            int k=v[x][i];
            if(dis[k]<min(dis[x],edge[x][k])){
                dis[k]=min(dis[x],edge[x][k]);
                if(!vis[k]){
                    vis[k]=1;
                    q.push(k);
                }
            }
        }
    }
}

poj 3268

题意:给你m个有向边,n个牛先从自己家去x点,再回去,问哪个牛走的最长

题解:把给的有向边正着存一份,以x为源点求最短路,可以得到每个牛回家的距离。

再把所有有向边都倒过来存一遍,以x为源点求最短路,得到的是每个牛去的时候的距离。

想加找最大即可,两次spfa的事。


poj3259

题意:这题难点就在于读题。有m条无向的路,还有w条有向的路(虫洞),A one way path from S to E that also moves the traveler back T seconds.意思是这条有向边的权值是负的,然后要求的是FJ能否回到起点,意思就是说有没有负环,如果有负环的话,他会一直在那个负环里转,因为权值每次都变小了。

题解:用spfa(bellman-ford)求负环即可

vector<int> v[505];
int edge[505][505];
int dis[505];
int vis[505];
int xcount[505];
int n,m,w;

void spfa(int u){
    queue<int> q;
    q.push(u);
    vis[u]=1;
    dis[u]=0;
    xcount[u]++;
    while(!q.empty()){
        int x=q.front();
        q.pop();
        vis[x]=0;
        for(int i=0;i<v[x].size();i++){
            int k=v[x][i];
            if(dis[k]>dis[x]+edge[x][k]){
                dis[k]=dis[x]+edge[x][k];
                if(!vis[k]){
                    vis[k]=1;
                    q.push(k);
                    xcount[k]++;
                    if(xcount[k]>n){
                        printf("YES\n");
                        return;
                    }
                }
            }
        }
    }
    printf("NO\n");
}

POJ 1502

题意:这题又是英语来卡人,是说从1到各个点的最短路中的最大值,说到这里就是个水题了,然而看懂题目才是最难的。


poj 3660 

题意:这题是给你m个有向边的关系,还有个确定有多少个牛的位置确定了

题解:Floyd暴力一遍,把所有有向边的关系都确定了,然后枚举每个牛,看他的入度出度之和是否为n-1

for(int k=1;k<=n;k++){
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                if(edge[i][k]&&edge[k][j]) edge[i][j]=1;
            }
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++){
        int flag=0;
        for(int j=1;j<=n;j++){
            if(i==j) continue;
            if(!(edge[i][j]||edge[j][i])) flag=1;
        }
        if(!flag) ans++;
    }
    printf("%d\n",ans);

poj 1511

这题就是个很显然的最短路,题目辣么长,然而难点在于数据量大!!!100w

题解:可以用dijkstra的堆优化和spfa来做。(刚学堆优化写的挫)

#include <iostream>
#include <cstdio>
#include <cctype>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <sstream>
#include <stack>

using namespace std;
#define MAX 1000000+5
#define MAXN 100000+5

typedef long long LL;
typedef unsigned long long ull;

const double pi=3.141592653589793;
const int INF=0x3f3f3f3f;
const int INFF=1e9;
const double inf=1e18;
const double eps=1e-10;
const int mod=1000000007;
const int prime=999983;

struct edge{
    int v,cost;
    edge(){}
    edge(int _v,int _cost):v(_v),cost(_cost){}
};

struct edge2{
    int u,v,w;
    edge2(){}
    edge2(int _u,int _v,int _w):u(_u),v(_v),w(_w){}
}a[MAX];

struct node{
    int id,val;
    node(){}
    node(int _id,int _v):id(_id),val(_v){}
    bool operator <(const node &a)const{                //重载<,使优先队列队首始终是val最小的元素
        return val>a.val;
    }
}x,y;

vector<edge> v[MAX];
int vis[MAX];
int dis[MAX];
int n,m;

LL dijkstra(int s){
    priority_queue<node> q;
    memset(vis,0,sizeof(vis));
    memset(dis,INF,sizeof(dis));
    x.id=s;
    x.val=0;
    dis[s]=0;
    q.push(x);
    while(!q.empty()){
        x=q.top();
        q.pop();
        int num=x.id;
        if(vis[num]) continue;
        vis[num]=1;
        for(int i=0;i<v[num].size();i++){
            int to=v[num][i].v;
            int cost=v[num][i].cost;
            if(!vis[to]&&dis[to]>dis[num]+cost){
                dis[to]=dis[num]+cost;
                y.id=to;
                y.val=dis[to];
                q.push(y);
            }
        }
    }
    LL sum=0;
    for(int i=1;i<=n;i++) sum+=dis[i];
    return sum;
}

int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        LL ans=0;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) v[i].clear();
        for(int i=1;i<=m;i++){
            int u,vv,w;
            scanf("%d%d%d",&u,&vv,&w);
            a[i]=edge2(u,vv,w);
            v[u].push_back(edge(vv,w));
        }
        ans+=dijkstra(1);
        for(int i=1;i<=n;i++) v[i].clear();
        for(int i=1;i<=m;i++){
            int u = a[i].u;
            int vv = a[i].v;
            int w = a[i].w;
            v[vv].push_back(edge(u,w));
        }
        ans+=dijkstra(1);
        printf("%lld\n",ans);
    }
    return 0;
}

下面是spfa的算法:时间复杂度和dijkstra的差不多(我以前用了LL 果断T了10次+)存结构体这种方法非常好,get

#include <iostream>
#include <cstdio>
#include <cctype>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <sstream>
#include <stack>

using namespace std;
#define MAX 1000000+5
#define MAXN 100000+5

typedef long long LL;
typedef unsigned long long ull;

const double pi=3.141592653589793;
const int INF=0x3f3f3f3f;
const int INFF=1e9;
const double inf=1e18;
const double eps=1e-10;
const int mod=1000000007;
const int prime=999983;

struct edge{
    int v,cost;
    edge(){}
    edge(int _v,int _c):v(_v),cost(_c){}
};
struct edge2{
    int u,v,w;
    edge2(){}
    edge2(int _u,int _v,int _w):u(_u),v(_v),w(_w){}
}a[MAX];
vector<edge> v[MAX];
int dis[MAX];
int vis[MAX];
int n,m;

LL spfa(int s){
    queue<int> q;
    memset(dis,INF,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dis[s]=0;
    vis[s]=1;
    q.push(s);
    while(!q.empty()){
        int x=q.front();
        q.pop();
        vis[x]=0;
        for(int i=0;i<v[x].size();i++){
            int k=v[x][i].v;
            int cost=v[x][i].cost;
            if(dis[k]>dis[x]+cost){
                dis[k]=dis[x]+cost;
                if(!vis[k]){
                    vis[k]=1;
                    q.push(k);
                }
            }
        }
    }
    LL sum=0;
    for(int i=1;i<=n;i++) sum+=dis[i];
    return sum;
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        LL ans=0;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) v[i].clear();
        for(int i=1;i<=m;i++){
            int u,vv,w;
            scanf("%d%d%d",&u,&vv,&w);
            a[i]=edge2(u,vv,w);
            v[u].push_back(edge(vv,w));
        }
        ans+=spfa(1);
        for(int i=1;i<=n;i++) v[i].clear();
        for(int i=1;i<=m;i++){
            int u = a[i].u;
            int vv = a[i].v;
            int w = a[i].w;
            v[vv].push_back(edge(u,w));
        }
        ans+=spfa(1);
        printf("%lld\n",ans);
    }
    return 0;
}

poj 3159

题意:给你a,b,c三个数意思是a认为b不能比他多c个糖,p[b]-p[a]<=c,即为 p[b]<=p[a]+c,这就是显然的最短路,详见差分约束系统http://blog.csdn.net/xuezhongfenfei/article/details/8685313

题解:这题就是数据量大,用vector建图过不了,用dijkstra+heap+前向星可以过,spfa+stack也轻松掠过。答案就是求p[n]-p[1]的最大值,即dis[n](感觉我差分也没全搞懂,改天还得学学)(dijkstra和spfa复杂度接近)


spfa+stack

#include <iostream>
#include <cstdio>
#include <cctype>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <sstream>
#include <stack>

using namespace std;
#define MAX 30000+5
#define MAXN 100000+5

typedef long long LL;
typedef unsigned long long ull;

const double pi=3.141592653589793;
const int INF=0x3f3f3f3f;
const int INFF=1e9;
const double inf=1e18;
const double eps=1e-10;
const int mod=1000000007;
const int prime=999983;

struct Edge{
    int v,cost,next;
}edge[150005];

struct node{
    int id,val;
    bool operator<(const node &a)const{
        return val>a.val;
    }
}x;
int head[30005];
int dis[30005];
int vis[30005];
int sstack[30005];
int tot;

inline int read_int()
{
    int ret=0;
    char tmp;
    while(!isdigit(tmp=getchar()));
    do{
        ret=(ret<<3)+(ret<<1)+tmp-'0';
    }while(isdigit(tmp=getchar()));
    return ret;
}

void add_edge(int a,int b,int c){
    edge[tot].v=b;
    edge[tot].cost=c;
    edge[tot].next=head[a];
    head[a]=tot++;
}


void spfa(int s){
    memset(vis,0,sizeof(vis));
    memset(dis,INF,sizeof(dis));
    int top=0;
    sstack[top++]=s;
    dis[s]=0;
    vis[s]=1;
    while(top!=0){
        int q=sstack[--top];
        vis[q]=0;
        for(int i=head[q];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            int cost=edge[i].cost;
            if(dis[v]>dis[q]+cost){
                dis[v]=dis[q]+cost;
                if(!vis[v]){
                    vis[v]=1;
                    sstack[top++]=v;
                }
            }
        }
    }
}
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    memset(head,-1,sizeof(head));
    tot=0;
    for(int i=0;i<m;i++){
        int a=read_int();
        int b=read_int();
        int c=read_int();
        add_edge(a,b,c);
    }
    spfa(1);
    printf("%d\n",dis[n]);
    return 0;
}

dijkstra+heap

#include <iostream>
#include <cstdio>
#include <cctype>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <sstream>
#include <stack>

using namespace std;
#define MAX 30000+5
#define MAXN 100000+5

typedef long long LL;
typedef unsigned long long ull;

const double pi=3.141592653589793;
const int INF=0x3f3f3f3f;
const int INFF=1e9;
const double inf=1e18;
const double eps=1e-10;
const int mod=1000000007;
const int prime=999983;

struct Edge{
    int v,cost,next;
}edge[150005];

struct node{
    int id,val;
    bool operator<(const node &a)const{
        return val>a.val;
    }
}x;
int head[30005];
int dis[30005];
int vis[30005];
int tot;

inline int read_int()
{
    int ret=0;
    char tmp;
    while(!isdigit(tmp=getchar()));
    do{
        ret=(ret<<3)+(ret<<1)+tmp-'0';
    }while(isdigit(tmp=getchar()));
    return ret;
}

void add_edge(int a,int b,int c){
    edge[tot].v=b;
    edge[tot].cost=c;
    edge[tot].next=head[a];
    head[a]=tot++;
}


void dijkstra(int s){
    memset(vis,0,sizeof(vis));
    memset(dis,INF,sizeof(dis));
    priority_queue<node> q;
    x.id=s;
    x.val=0;
    dis[s]=0;
    q.push(x);
    while(!q.empty()){
        x=q.top();
        q.pop();
        int num=x.id;
        if(vis[num]) continue;
        vis[num]=1;
        for(int i=head[num];i!=-1;i=edge[i].next){
            int vv=edge[i].v;
            int cost=edge[i].cost;
            if(!vis[vv]&&dis[vv]>dis[num]+cost){
                dis[vv]=dis[num]+cost;
                x.id=vv;
                x.val=dis[vv];
                q.push(x);
            }
        }
    }
}
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    memset(head,-1,sizeof(head));
    tot=0;
    for(int i=0;i<m;i++){
        int a=read_int();
        int b=read_int();
        int c=read_int();
        add_edge(a,b,c);
    }
    dijkstra(1);
    printf("%d\n",dis[n]);
    return 0;
}

poj 1062

题意:一个比较明显的最短路,加上了等级。

题解:枚举最高等级,然后把等级不满足的点直接vis[x]=1记作已经访问过。

然后dijkstra即可

for(int i=mini;i<=maxn;i++){
        memset(vis,0,sizeof(vis));
        memset(dis,INF,sizeof(dis));
        for(int j=1;j<=n;j++){
            if(level[j]>i||i-level[j]>m) vis[j]=1;
        }
        dis[0]=0;
        while(1){
            int x=n+1;
            for(int i=0;i<=n;i++){
                if(!vis[i]&&dis[i]<dis[x]) x=i;
            }
            if(x==n+1) break;
            vis[x]=1;
            for(int i=0;i<=n;i++){
                if(!vis[i]) dis[i]=min(dis[i],dis[x]+edge[x][i]);
            }
        }
        ans=min(ans,dis[1]);
    }
    printf("%d\n",ans);


lightoj 1074

题意:很明显是最短路哇

题解:spfa判下负环即可。水水哒

/**********************************************************************************************************************************************************************************/

HDU 4370(转自kuangbin大神blog)(绝对好题***)

显然,题目给的是一个0/1规划模型。

解题的关键在于如何看出这个模型的本质。

3个条件明显在刻画未知数之间的关系,从图论的角度思考问题,容易得到下面3个结论:

1.X12+X13+...X1n=1 于是1号节点的出度为1

2..X1n+X2n+...Xn-1n=1 于是n号节点的入度为1

3.∑Xki =∑Xij 于是2~n-1号节点的入度必须等于出度

于是3个条件等价于一条从1号节点到n号节点的路径,故Xij=1表示需要经过边(i,j),代价为Cij。Xij=0表示不经过边(i,j)。注意到Cij非负且题目要求总代价最小,因此最优答案的路径一定可以对应一条简单路径。

最终,我们直接读入边权的邻接矩阵,跑一次1到n的最短路即可,记最短路为path。

以上情况设为A

非常非常非常非常非常非常非常非常抱歉,简单路径只是充分条件,但不必要。(对造成困扰的队伍深表歉意)

漏了如下的情况B:

从1出发,走一个环(至少经过1个点,即不能是自环),回到1;从n出发,走一个环(同理),回到n。

容易验证,这是符合题目条件的。且A || B为该题要求的充要条件。

由于边权非负,于是两个环对应着两个简单环。

本程序用SPFA来完成最短路。
但是由于要计算从出发点出发的闭环的路径长度。
所以要在普通SPFA的基础上做点变化。

就是把dist[start]设为INF。同时一开始并不是让出发点入队,而是让
出发点能够到达的点入队。

故最终答案为min(path,c1+c2)(用前向星建图比较好)

<span style="font-size:12px;">#include <iostream>
#include <cstdio>
#include <cctype>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <sstream>
#include <stack>

using namespace std;
#define MAX 30000+5
#define MAXN 100000+5

typedef long long LL;
typedef unsigned long long ull;

const double pi=3.141592653589793;
const int INF=0x3f3f3f3f;
const int INFF=1e9;
const double inf=1e18;
const double eps=1e-10;
const int mod=1000000007;
const int prime=999983;

inline int read_int()
{
    int ret=0;
    char tmp;
    while(!isdigit(tmp=getchar()));
    do{
        ret=(ret<<3)+(ret<<1)+tmp-'0';
    }while(isdigit(tmp=getchar()));
    return ret;
}

struct Edge{
    int v,cost,next;
}edge[100000];
int head[305];
int dis[305];
int vis[305];
int tot;

void add_edge(int a,int b,int c){
    edge[tot].v=b;
    edge[tot].cost=c;
    edge[tot].next=head[a];
    head[a]=tot++;
}

void spfa(int s){
    memset(vis,0,sizeof(vis));
    memset(dis,INF,sizeof(dis));
    queue<int> q;
    for(int i=head[s];i!=-1;i=edge[i].next){
        int k=edge[i].v;
        if(k!=s){
            dis[k]=edge[i].cost;
            vis[k]=1;
            q.push(k);
        }
    }
    while(!q.empty()){
        int x=q.front();
        q.pop();
        vis[x]=0;
        for(int i=head[x];i!=-1;i=edge[i].next){
            int k=edge[i].v;
            int cost=edge[i].cost;
            if(dis[k]>dis[x]+cost){
                dis[k]=dis[x]+cost;
                if(!vis[k]){
                    vis[k]=1;
                    q.push(k);
                }
            }
        }
    }
}

int main(){
    int n;
    while(~scanf("%d",&n)){
        memset(edge,INF,sizeof(edge));
        memset(head,-1,sizeof(head));
        tot=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                int a;
                scanf("%d",&a);
                add_edge(i,j,a);
            }
        }
        spfa(1);
        int path=dis[n];
        int c1=dis[1];
        spfa(n);
        int c2=dis[n];
        printf("%d\n",min(path,c1+c2));
    }
    return 0;
}

poj 3169

题意:当排队等候喂食时,奶牛喜欢和它们的朋友站得靠近些。FJ有N(2<=N<=1000)头奶牛,编号从1到N,沿一条直线站着等候喂食。奶牛排在队伍中的顺序和它们的编号是相同的。因为奶牛相当苗条,所以可能有两头或者更多奶牛站在同一位置上。即使说,如果我们想象奶牛是站在一条数轴上的话,允许有两头或更多奶牛拥有相同的横坐标。

一些奶牛相互间存有好感,它们希望两者之间的距离不超过一个给定的数L。另一方面,一些奶牛相互间非常反感,它们希望两者间的距离不小于一个给定的数D。给出ML条关于两头奶牛间有好感的描述,再给出MD条关于两头奶牛间存有反感的描述。(1<=ML,MD<=10000,1<=L,D<=1000000)

你的工作是:如果不存在满足要求的方案,输出-1;如果1号奶牛和N号

奶牛间的距离可以任意大,输出-2;否则,计算出在满足所有要求的情况下,1号奶牛和N号奶牛间可能的最大距离。


题解:这题给出了一些好感的关系,首先题目说每个牛站的位置是按照标号顺序的,所以3号的位置肯定大于等于1号。

所以一种情况就是AB最大相差C,就是B-A<=C,即为B<=A+C,这是A->B之间有一条权值C的有向边。

AB相差最小为C,就是B-A>=C,即为B>=A+C,化成A<=B-C,这是B->A之间有一条权值为-C的有向边

建图之后spfa跑一遍(因为有负权值),如果dis[n]==INF的时候就是1-n之间的没有最短路,可以任意距离,输出-2

有负环就是-1这个队伍不能排(我一开始-1 -2搞反了)

<span style="font-size:12px;">#include <iostream>
#include <cstdio>
#include <cctype>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <sstream>
#include <stack>

using namespace std;
#define MAX 30000+5
#define MAXN 100000+5

typedef long long LL;
typedef unsigned long long ull;

const double pi=3.141592653589793;
const int INF=0x3f3f3f3f;
const int INFF=1e9;
const double inf=1e18;
const double eps=1e-10;
const int mod=1000000007;
const int prime=999983;

inline int read_int()
{
    int ret=0;
    char tmp;
    while(!isdigit(tmp=getchar()));
    do{
        ret=(ret<<3)+(ret<<1)+tmp-'0';
    }while(isdigit(tmp=getchar()));
    return ret;
}

struct Edge{
    int v,cost,next;
}edge[20000];
int head[1005];
int dis[1005];
int vis[1005];
int xcount[1005];
int tot;
int flag;

void add_edge(int a,int b,int c){
    edge[tot].v=b;
    edge[tot].cost=c;
    edge[tot].next=head[a];
    head[a]=tot++;
}

void spfa(int s,int n){
    memset(vis,0,sizeof(vis));
    memset(dis,INF,sizeof(dis));
    memset(xcount,0,sizeof(xcount));
    queue<int> q;
    dis[s]=0;
    vis[s]=1;
    xcount[s]++;
    q.push(s);
    while(!q.empty()){
        int x=q.front();
        q.pop();
        vis[x]=0;
        for(int i=head[x];i!=-1;i=edge[i].next){
            int k=edge[i].v;
            int cost=edge[i].cost;
            //printf("%d %d %d \n",x,k,cost);
            if(dis[k]>dis[x]+cost){
                dis[k]=dis[x]+cost;
                if(!vis[k]){
                    vis[k]=1;
                    xcount[k]++;
                    q.push(k);
                    if(xcount[k]>n){
                        flag=1;
                        return ;
                    }
                }
            }
        }
    }
}

int main(){
    int n,l,d;
    scanf("%d%d%d",&n,&l,&d);
    tot=0;
    memset(head,-1,sizeof(head));
    for(int i=0;i<l;i++){
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        add_edge(a,b,c);
    }
    for(int i=0;i<d;i++){
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        add_edge(b,a,-c);
    }
    flag=0;
    spfa(1,n);
    if(flag) printf("-1\n");
    else if(dis[n]==INF) printf("-2\n");
    else printf("%d\n",dis[n]);
    return 0;
}
</span>


hdu 4725

题意:给你n个点,每个点属于某个层,点之间有m条无向边,相邻的层之间还能互相走,花费是c

题解:首先看百度上说要拆点,后来学长没用拆点就过去了。

记录每个层有哪些点,然后用dijkstra+heap的时候,点的结构体中要加个判断is_node,如果是点,他就可以走向他所连的边,还有他的上一层或者下一层,都进队。

如果是层,那么可以把这层上的所有点(未访问过并且dis被更新过的)放进队列中,即可。(前向星建图head没有初始化又看了好久,还得多练,这题也是虚掉了不敢做,so weak)

#include <iostream>
#include <cstdio>
#include <cctype>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <sstream>
#include <stack>

using namespace std;
#define MAX 30000+5
#define MAXN 100000+5

typedef long long LL;
typedef unsigned long long ull;

const double pi=3.141592653589793;
const int INF=0x3f3f3f3f;
const int INFF=1e9;
const double inf=1e18;
const double eps=1e-10;
const int mod=1000000007;
const int prime=999983;

inline int read_int(){
    int ret=0;
    char tmp;
    while(!isdigit(tmp=getchar()));
    do{
        ret=(ret<<3)+(ret<<1)+tmp-'0';
    }while(isdigit(tmp=getchar()));
    return ret;
}

struct Node{
    int v,val;
    bool is_node;
    bool operator < (const Node &a)const{
        return val > a.val;
    }
};
struct Edge{
    int v,cost,next;
}edge[2*MAXN];
int n,m,c;
vector<int> v[MAXN];
int lay[MAXN];
int head[MAXN];
int dis[MAXN];
int vis[MAXN];
int vis_l[MAXN];
int tot;
int max_l,min_l;

void add_edge(int a,int b,int c){
    edge[tot]=(Edge){b,c,head[a]};
    head[a]=tot++;
}

void dijkstra(int s){
    memset(vis,0,sizeof(vis));
    memset(vis_l,0,sizeof(vis_l));
    memset(dis,INF,sizeof(dis));
    priority_queue<Node> q;
    q.push((Node){s,0,1});
    dis[s]=0;
    while(!q.empty()){
        Node now=q.top();
        q.pop();
        int num=now.v;
        if(now.is_node){
            if(vis[num]) continue;
            vis[num]=1;
            for(int i=head[num];i!=-1;i=edge[i].next){
                int k=edge[i].v;
                int cost=edge[i].cost;
                if(!vis[k]&&dis[k]>dis[num]+cost){
                    dis[k]=dis[num]+cost;
                    q.push((Node){k,dis[k],1});
                }
            }
            if(lay[num]>min_l){
                q.push((Node){lay[num]-1,dis[num]+c,0});
            }
            if(lay[num]<max_l){
                q.push((Node){lay[num]+1,dis[num]+c,0});
            }
        }
        else{
            if(vis_l[num]) continue;
            vis_l[num]=1;
            for(int i=0;i<v[num].size();i++){
                int k=v[num][i];
                if(!vis[k]&&dis[k]>now.val){
                    dis[k]=now.val;
                    q.push((Node){k,dis[k],1});
                }
            }
        }
    }
}
int main(){
    int T;
    scanf("%d",&T);
    for(int t=1;t<=T;t++){
        scanf("%d%d%d",&n,&m,&c);
        tot=0;
        max_l=0;
        min_l=INF;
        memset(head,-1,sizeof(head));
        for(int i=1;i<=n;i++) v[i].clear();
        for(int i=1;i<=n;i++){
            scanf("%d",&lay[i]);
            v[lay[i]].push_back(i);
            max_l=max(max_l,lay[i]);
            min_l=min(min_l,lay[i]);
        }
        for(int i=0;i<m;i++){
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            add_edge(a,b,c);
            add_edge(b,a,c);
        }
        dijkstra(1);
        printf("Case #%d: ",t);
        if(dis[n]==INF) printf("-1\n");
        else printf("%d\n",dis[n]);
    }
    return 0;
}

还有个神马最短路+最大流还不会,改天做完了再发



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值