样例版子floyed:求任两点之间的最短路径加打印路径,最短路拼接

该博客讨论了如何寻找城市间的最短路径,并在道路损坏后如何确定哪些城市对交通至关重要。它提供了样例输入输出,涉及图论和算法问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

来源(https://www.cnblogs.com/liyinggang/p/5528944.html)
问题描述
这是春天乡村的N个城市。每对城市之间可能有一条或没有一条交通线。
现在有一些货物应该从一个城市运到另一个城市。
运输费由两部分组成: 这些城市之间的交通成本,以及任何货物通过一个城市时,除来源地和目的地城市外,都要征收一定的税。
您必须编写一个程序来查找成本最低的路线。
输入 第一个是n,城市数量。n=0表示输入结束。
输入中给出了路径成本、城市税、源城市和目的城市的数据,其形式如下:
a11 a12 … a1N
a21 a22 … a2N

aN1 aN2 … aNN
b1 b2 … bN

c d
e f

g h
其中aij是从城市i到城市j的运输成本,aij=-1表示城市i和城市j之间没有直接路径。bi表示通过城市i的税收。货物将从城市c运送到城市d,城市e运送到城市f,…,g=h=-1。您必须输出经过的城市序列和总成本,其形式为:
Output
From c to d :
Path: c–>c1–>…–>ck–>d
Total cost : …

From e to f :
Path: e–>e1–>…–>ek–>f
Total cost : …
注意:如果有更多的最小路径,则输出词汇上最小的路径。在每个测试用例后打印一个空白行。
Sample Input

5
0 3 22 -1 4
3 0 5 -1 -1
22 5 0 9 20
-1 -1 9 0 4
4 -1 20 4 0
5 17 8 3 1
1 3
3 5
2 4
-1 -1
0

Sample Output

From 1 to 3 :
Path: 1–>5–>4–>3
Total cost : 21

From 3 to 5 :
Path: 3–>4–>5
Total cost : 16

From 2 to 4 :
Path: 2–>1–>5–>4
Total cost : 17

#include<cstdio> 
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int N=200;
int G[N][N];//记录费用 
int path[N][N];//记录途径 
int cost[N];
int main()
{
 int n;
 while(cin>>n&&n)
 {
  for(int i=1;i<=n;i++)
   for(int j=1;j<=n;j++)
   {
    cin>>G[i][j];
    if(G[i][j]==-1) G[i][j]=INF;
    path[i][j]=j;
   }
  for(int i=1;i<=n;i++) cin>>cost[i];
  for(int k=1;k<=n;k++)
   for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)//floyed 
     if(G[i][j]>G[i][k]+G[k][j]+cost[k])
      G[i][j]=G[i][k]+G[k][j]+cost[k],path[i][j]=path[i][k];
     else if(G[i][j]==G[i][k]+G[k][j]+cost[k]&&path[i][j]>path[i][k])
      path[i][j]=path[i][k];//判断修改路径的条件 
  int a,b;
  while(cin>>a>>b)
  {
   if(a==b&&a==-1) break;
   printf("From %d to %d :\nPath: %d",a,b,a);
   int u=a,v=b;
   while(u!=v)//输出路径 
   {
    printf("-->%d",path[u][v]);
    u=path[u][v]; 
   }
  printf("\nTotal cost : %d\n\n",G[a][b]);
  }
 }
 return 0;
}

最短路拼接
来源:(https://www.cnblogs.com/wjyyy/p/lg1841.html)
题目描述
参加jsoi冬令营的同学最近发现,由于南航校内修路截断了原来通向计算中心的路,导致去的路程比原先增加了近一公里。而食堂门前施工虽然也截断了原来通向计算中心的路,却没有使路程增加,因为可以找到同样长度的路作替代。其实,问题的关键在于,路截断的地方是交通要点。

同样的情况也出现在城市间的交通中。某些城市如果出了问题,可能会引起其他很多城市的交通不便。另一些城市则影响不到别的城市的交通。jsoi冬令营的同学发现这是一个有趣的问题,于是决定研究这个问题。

他们认为这样的城市是重要的:如果一个城市c被破坏后,存在两个不同的城市a和b(a, b均不等于c),a到b的最短距离增长了(或不通),则城市c是重要的。

jsoi冬令营的同学面对着一张教练组交给他们的城市间交通图,他们希望能找出所有重要的城市。现在就请你来解决这个问题。

输入输出格式
输入格式:
第一行两个整数N,M,N为城市数,M为道路数。

接下来M行,每行三个整数,表示两个城市之间的无向边,以及之间的路的长度。

输出格式:
一行,按递增次序输出若干的数,表示重要的城市。

如果没有点的话需要输出一行
“No important cities.”
去掉引号。

输入输出样例

输入样例#1:
4 4
1 2 1
2 3 1
4 1 2
4 3 2

输出样例#1:
2

说明
30%的数据:N≤20N≤20;

60%的数据:N≤100N≤100;

100%的数据:N≤200,M≤N×(N−1)2,0<c≤10000N≤200,M≤N×(N−1)2,0<c≤10000。cc即路的长度。

保证不出现重边和自环

感谢@赵昕鹏 和@qq2477259579 提供程序

#include<cstdio>
#include<cstring>
#include<bitset>
using std::bitset;
bitset<210> im[210][210];
int f[210][210];
int is[210];
int main()
{
    memset(f,0x3f,sizeof(f));
    int u,v,n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        f[i][i]=0;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&u,&v);
        scanf("%d",&f[u][v]);
        f[v][u]=f[u][v];
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            im[i][j][i]=1;//初始化设两端为重要城市
            im[i][j][j]=1;
        }
 
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(f[i][k]+f[k][j]==f[i][j])
                    im[i][j]&=(im[i][k]|im[k][j]);//当更新计数时取交集
                else if(f[i][k]+f[k][j]<f[i][j])//当更新最短路时直接赋值为两段的并集
                {
                    f[i][j]=f[i][k]+f[k][j];
                    im[i][j]=im[i][k]|im[k][j];
                }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            for(int k=1;k<=n;k++)
                if(k!=i&&k!=j)//注意特判
                    if(im[i][j][k])
                        is[k]=1;
    int flag=0;
    for(int i=1;i<=n;i++)
        if(is[i])
        {
            flag=1;
            printf("%d ",i);
        }
    if(!flag)//注意判断无解
        puts("No important cities.");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值