迷阵突围 (dijkstra求次短路)邻接表,邻接矩阵

 分析:dijkstra算法求最短路问题。先求最短路,再依次删除最短路上的边,每次删除一条,使用dijkstra求此时的最短路,更新最小值,最后得到第二短路。f标记删除与否,抑或便于寻找无向图的两条边。

邻接表: 

#include<stdio.h>
#include<string.h>
#include<math.h>
#define inf 1.0e+10
int n,m;
struct node {
    int x,y;
}a[205];
struct edge {
    int v,next,f; //1有效,0无效
    double w;
}e[40005];
int p[205],eid,s;
int vis[205],pre[205];
int path[205],cnt;
double d[205],min;
void insert(int u,int v,double w) {
    struct edge t={v,p[u],1,w};
    e[eid]=t;
    p[u]=eid++;
}
void insert2(int u,int v,double w) {
    insert(u,v,w);
    insert(v,u,w);
}
double dist(int u,int v) {
    double dx=a[u].x-a[v].x;
    double dy=a[u].y-a[v].y;
    return sqrt(dx*dx+dy*dy);
}
void getpath(int x) {
    if(x==1) {path[cnt]=1;return ;}
    path[cnt++]=x;
    getpath(pre[x]);
}

void dijkstra() {
    for(int i=1;i<=n;i++){
        d[i]=inf;
    } 
    memset(vis,0,sizeof(vis));
    s=1;
    d[s]=0;
    for(int i=1;i<=n;i++) {
        double mind=inf;
        int u=0;
        for(int j=1;j<=n;j++) {
            if(!vis[j]&&d[j]<mind){
                mind=d[j];
                u=j;
            }
        }
        if(mind==inf) break;
        vis[u]=1;
        for(int j=p[u];~j;j=e[j].next) {          
            if(e[j].f) {   //第一次找最短路时f均为1
                int v=e[j].v;
                if(d[v]>d[u]+e[j].w) {                
                    d[v]=d[u]+e[j].w;
                    pre[v]=u; //记录前一个点,只在第一次找最短路时有用处
                }               
            }
        }
    }
     if(d[n]<min) min=d[n];    
}
int main() {
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) {
        scanf("%d%d",&a[i].x,&a[i].y);
    } 
    memset(p,-1,sizeof(p));
    for(int i=1;i<=m;i++) {
        int u,v;
        scanf("%d%d",&u,&v);
        insert2(u,v,dist(u,v));
    }
    dijkstra();
    getpath(n);
    min=inf;
    for(int i=0;i<cnt;i++) {
        int u1=path[i],v1=path[i+1];
        for(int j=p[u1];~j;j=e[j].next){
            if(e[j].v==v1) {
                e[j].f=0;   //删除最短路径上的一条边
                e[j^1].f=0;   //无向图两条边序号相邻,用抑或处理
                dijkstra();
                e[j].f=1;
                e[j^1].f=1;
            }
        }
    }
    if(min==inf) printf("-1");
    else
    printf("%.2f",min);
    return 0;
}

邻接矩阵:n较小可使用

#include<stdio.h>
#include<string.h>
#include<math.h>
#define inf 1.0e+10
int n,m;
int f[205][205],vis[205],s,pre[205],x[205],y[205];
double g[205][205],d[205],min;
double dist(int u,int v) {
    return sqrt((x[u]-x[v])*(x[u]-x[v])+(y[u]-y[v])*(y[u]-y[v]));
}
void dijkstra(int flag) {
    for(int i=1;i<=n;i++) d[i]=inf;
    memset(vis,0,sizeof(vis));
    s=1;
    d[s]=0;
    for(int i=1;i<=n;i++) {
        double mind=inf;
        int u=0;
        for(int j=1;j<=n;j++) {
            if(!vis[j]&&d[j]<mind){
                mind=d[j];
                u=j;
            }
        }
        if(mind==inf) break;
        vis[u]=1;
        for(int j=1;j<=n;j++) {
            if(g[u][j]!=inf) {//有边
                if(f[u][j]) {//第一次找最短路时f均为1                   
                    if(d[j]>d[u]+g[u][j]) {
                        d[j]=d[u]+g[u][j];
                        if(flag) pre[j]=u; //第一次找最短路时记录前一个点
                    }
                }
            }
        }
    }
     if(d[n]<min) min=d[n];    
}

int main() {
    memset(f,1,sizeof(f));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) {
        scanf("%d%d",&x[i],&y[i]);
    }
    for(int i=1;i<=n;i++) {
        for(int j=1;j<=n;j++) {
            g[i][j]=inf;
        }
    }
    for(int i=1;i<=m;i++) {
        int u,v;
        scanf("%d%d",&u,&v);
        g[u][v]=g[v][u]=dist(u,v);
        
    }
    dijkstra(1);
    min=inf;
    for(int i=n;i!=1;i=pre[i]) {
        int u=i,v=pre[i];
        f[u][v]=f[v][u]=0;//delete
        dijkstra(0);
        f[u][v]=f[v][u]=1;
    }
    if(min==inf) printf("-1");
    else
    printf("%.2f",min);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值