k短路

问题 A: k短路

时间限制: 2 Sec 内存限制: 256 MB

题目描述

有n个城市和m条单向道路,城市编号为1~n。每条道路连接两个不同的城市,且任意两条道路要么起点不同要么终点不同,因此n和m满足m<=n(n-1)。给定两个城市a和b,可以给a到b的所有简单路(所有城市最多经过一次,包括起点和终点)排序:先按长度从小到大排序,长度相同时按照字典序从小到大排序。你的任务是求出a到b的第k短路。

输入

输入第一行包含五个正整数n, m, k, a, b。以下m行每行三个整数u, v, l,表示从城市u到城市v有一条长度为l的单向道路。100%的数据满足:2<=n<=50, 1<=k<=200

输出

如果a到b的简单路不足k条,输出No,否则输出第k短路:从城市a开始依次输出每个到达的城市,直到城市b,中间用减号”-“分割。

样例输入

5 20 10 1 5
1 2 1
1 3 2
1 4 1
1 5 3
2 1 1
2 3 1
2 4 2
2 5 2
3 1 1
3 2 2
3 4 1
3 5 1
4 1 1
4 2 1
4 3 1
4 5 2
5 1 1
5 2 1
5 3 1
5 4 1

样例输出

1-2-4-3-5

提示

第一个例子有5个城市,所有可能出现的道路均存在。从城市1到城市5一共有5条简单路

Code
#include <bits/stdc++.h>
using namespace std;
const int mxn = 51, mxm = 3001, mxk = 201, INF = ~0U >> 2;
struct edge {
    int u,v,w,pre,nex;
}e[mxn+mxm],f[mxn+mxm];
struct data{
    int u,v,w;
    bool operator < (data B) const {
        return v<B.v;
    }
}tmp[mxm];
int n,m,k,a,b,dist[mxn],Q[mxn+1],tot;
int z,z0,No,len1,visit[mxn],tmps[mxn],len[mxk],sheet[mxk][mxn],sum[mxk],tmpl,ansl,ans[mxn];
bool vis[mxn],ok;
void read(int &k) {
    int f=1;
    char ch=getchar();
    while ((ch<48||ch>57)&&ch!='-') ch=getchar();
    if (ch=='-') f=-1,ch=getchar();
    k=0;
    while (ch>=48&&ch<=57) k=k*10+ch-48,ch=getchar();
    k*=f;
}
void add_edge(int u,int v,int w) {
    e[tot]=(edge){u,v,w,e[u].pre,u};
    e[u].pre=tot;
    e[e[tot].pre].nex=tot;
    f[tot]=(edge){v,u,w,f[v].pre,v};
    f[v].pre=tot;
    f[f[tot].pre].nex=tot++;
}
void dfs(int x, int ss) {
    if (x == b) {
        if (ss <= z) {
            sum[No] = ss;
            len[No] = len1;
            for (int i=0; i<len1; ++i) sheet[No][i] = tmps[i];
            No++;
            if (No == k) ok = 1;
        }
        else if (ss < z0) z0 = ss;
        return;
    } else {
        int h0 = ss + dist[x];
        if (h0 > z) {
            if (h0 < z0) z0 = h0;
            return;
        }
        visit[x] = ++tmpl;
        Q[0] = x;
        int u, v, l = -1, r = 0;
        while (l<r) {
            u = Q[++l];
            for (int p=e[u].nex; p!=u; p=e[p].nex) {
                v = e[p].v;
                if (!vis[v] && visit[v]!=tmpl) {
                    visit[v] = tmpl;
                    Q[++r] = v;
                }
            }
        }
        if (visit[b] != tmpl) return;
        for (int p=e[x].nex; p!=x; p=e[p].nex) {
            v = e[p].v;
            if (!vis[v]) {
                vis[v] = 1;
                tmps[len1++] = v;
                dfs(v, ss + e[p].w);
                if (ok) return;
                else {
                    len1--;
                    vis[v] = 0;
                }
            }
        }
    }
}
void solve() {
    z = dist[a], tmpl = 0;
    int No0 = 0;
    while (1) {
        z0 = INF, No = 0;
        memset(vis,0,sizeof(vis));
        memset(visit,0,sizeof(visit));
        vis[a] = 1;
        len1 = 1;
        tmps[0] = a;
        dfs(a, 0);
        if (ok) {
            No0 = k - No0;
            for (int i=0; i<k; ++i)
                if (sum[i] == z) {
                    No0--;
                    if (!No0) {
                        ansl = len[i];
                        for (int j=0; j<len[i]; ++j) ans[j] = sheet[i][j];
                    }
                }
            break;
        } else
            if (z0 == INF) break;
            else {
                No0 = No;
                z = z0;
            }
    }
}
int main() {
    read(n); read(m); read(k); read(a); read(b);
    a--;
    b--;
    for (int i=0;i<n;++i) e[i].pre=e[i].nex=f[i].pre=f[i].nex=i;
    tot=n;
    for (int i=0;i<m;++i) {
        read(tmp[i].u); read(tmp[i].v); read(tmp[i].w);
        tmp[i].u--;
        tmp[i].v--;
    }
    sort(tmp,tmp+m);
    for (int i=0;i<m;++i) add_edge(tmp[i].u,tmp[i].v,tmp[i].w);

    for (int i=0;i<n;++i) {
        vis[i]=0;
        dist[i]=INF;
    }
    vis[b]=1;
    dist[b]=0;
    Q[0]=b;
    int l=0,r=0;
    while (!(!l&&r==n||l==r+1)) {
        int u=Q[l], x=dist[u];
        for (int p=f[u].nex; p!=u; p=f[p].nex) {
            int v=f[p].v, y=x+f[p].w;
            if (y<dist[v]) {
                dist[v]=y;
                if (!vis[v]) {
                    vis[v]=1;
                    Q[r==n ? r=0 : ++r]=v;
                }
            }
        }
        vis[u]=0;
        l==n ? l=0 : l++;
    }

    solve();

    if (ok) {
        printf("%d", ans[0] + 1);
        for (int i = 1; i < ansl; ++i) printf("-%d",ans[i] + 1);
        printf("\n");
    } else printf("No\n");

    return 0;
}

/**************************************************************
    Problem: 4131
    User: WC006
    Language: C++
    Result: 正确
    Time:1420 ms
    Memory:1904 kb
****************************************************************/
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你好!对于K短路算法的实现,你可以使用Matlab编程语言来完成。以下是一个简单的示例代码: ```matlab function [paths, costs] = kShortestPaths(graph, source, target, k) % 初始化变量 paths = cell(k, 1); costs = zeros(k, 1); pathCount = 0; % 执行Dijkstra算法,找到最短路径 [shortestPath, shortestCost] = dijkstra(graph, source, target); % 将最短路径添加到结果中 paths{1} = shortestPath; costs(1) = shortestCost; pathCount = 1; % 迭代查找更多的路径 while pathCount < k % 移除最短路径上的一边 graph = removeEdge(graph, shortestPath); % 执行Dijkstra算法,找到下一短路径 [nextPath, nextCost] = dijkstra(graph, source, target); % 如果找不到更多路径,则退出循环 if isempty(nextPath) break; end % 将下一短路径添加到结果中 pathCount = pathCount + 1; paths{pathCount} = nextPath; costs(pathCount) = nextCost; % 更新最短路径和最短成本 shortestPath = nextPath; shortestCost = nextCost; end end function [path, cost] = dijkstra(graph, source, target) % 初始化变量 nodeCount = size(graph, 1); visited = false(nodeCount, 1); distance = inf(nodeCount, 1); prevNode = zeros(nodeCount, 1); % 设置起点的距离为0 distance(source) = 0; % 执行Dijkstra算法 for i = 1:nodeCount % 找到当前距离最小的节点 [~, currentNode] = min(distance); % 标记该节点为已访问 visited(currentNode) = true; % 如果到达目标节点,则停止算法 if currentNode == target break; end % 更新相邻节点的距离和前驱节点 for j = 1:nodeCount if graph(currentNode, j) > 0 && ~visited(j) newDistance = distance(currentNode) + graph(currentNode, j); if newDistance < distance(j) distance(j) = newDistance; prevNode(j) = currentNode; end end end % 将当前节点的距离设置为无穷大,防止重复访问 distance(currentNode) = inf; end % 构造最短路径 path = target; while prevNode(path(end)) ~= 0 path = [prevNode(path(end)); path]; end % 计算最短成本 cost = distance(target); end function graph = removeEdge(graph, path) for i = 1:length(path)-1 graph(path(i), path(i+1)) = 0; end end ``` 你可以根据自己的需求对该代码进行修改和扩展。希望对你有所帮助!如果你对其他问题有疑问,欢迎继续提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值