NYOJ-931-货物运输【floyed+路径还原】

货物运输

时间限制: 1000 ms  |  内存限制: 65535 KB
难度: 4
描述

S国有n个城市,从a城到b城运货的花费有两部分组成:

(1)a城到b城的运输费

(2)途径城市的税收

例如:运货到 b,走路线> i > j > b ,总花费为到 到 j到 的运输费、i城市的税收之和。

已知任意两个城市的运输费用,每个城市的税收,计算出,城市ab的最小运输费。

输入
多组数据。
第一行输入整数n(n不大于200,城市从1开始编号)
接下来输入n行n列的矩阵M,Mij 表示 i 城市到 j 城市的运输费,-1表示这两个城市不能直接到达。
第n+2 行 输入n个整数,第i个整数代表第i个城市的税收。
第n+3 行 输入整数m,表示有m次询问(m不大于200)。
接下来m行,每行输入两个整数u, v。
输出
对于每次询问
输出如下:
From u to v :
Path: u-->c1-->......-->ck-->v
Total cost : 

............

From e to f :
Path: e-->e1-->..........-->ek-->f
Total cost : ......


Note: 如果有多种路径方案,输出字典序最小的,每次询问后加一个换行。a城市到a城市的运费不一定为0
样例输入
4
0 5 15 -1
5 0 5 8
15 10 2 5
-1 -1 8 0
5 3 7 1
3
1 3
2 4
3 1
样例输出
From 1 to 3 :
Path: 1-->2-->3
Total cost : 13

From 2 to 4 :
Path: 2-->4
Total cost : 8

From 3 to 1 :
Path: 3-->1
Total cost : 15

 //931
/*这道题就是求最短路并且路径还原的问题。本身挺简单
但是因为字典序处理不好错误了好多次,哭瞎。
我用了一个pre[i][j],数组,表示记录j->i的第一中间点。
那么
int F=i,T=j;
do
{
	T=pre[F][T];
}while(F!=T);
递推下去就能遍历从j->i(不包括i)这些点。
pre[i][j],这个数组初始化当然为i。假如g[i][j]被更改,即i->j的路径被更改。
pre[i][j->i],就得随之改变自己的前驱。
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stack>
#define Maxsize 300
#define inf 0x3f3f3f3f
using namespace std;
stack<int> sta;
int g[Maxsize][Maxsize];
int cost[Maxsize];
int pre[Maxsize][Maxsize];
int n;
int s1[Maxsize];
int s2[Maxsize];
int intcmp(int *a,int *b)
{//判断字典序。a的字典序小的话返回1
	int len1=0;
	int len2=0;
	for(len1=0;a[len1]!=-1;len1++);
	for(len2=0;b[len2]!=-1;len2++);
	for(int i=len1-1,j=len2-1;i>=0&&j>=0;i--,j--)
	{
		if(a[i]<b[j])
			return 1;
		else if(a[i]>b[i])
			return -1;
	}
	return 0;
}
void floyed()
{
	int i,j,k;
	for(i=1;i<=n;i++)
		for(j=1;j<=n;j++)
		{
			pre[i][j]=i;
			if(g[i][j]==-1)
			{
				g[i][j]=inf;
			}
		}
	for(k=1;k<=n;k++)
		for(i=1;i<=n;i++)
			for(j=1;j<=n;j++)
			{//Floyed算法本身是个DP,所以改变判定条件就可以解决过路费的问题
				if(g[i][j]>g[i][k]+g[k][j]+cost[k])
				{
					g[i][j]=g[i][k]+g[k][j]+cost[k];
					//i->k路径不用更新
					//将k->j路径的点同步到,i->j上。
					int p,q;
					p=k;q=j;
					do
					{
						pre[i][q]=pre[p][q];
						q=pre[p][q];
					}while(q!=p);
				}
				else if(g[i][j]==g[i][k]+g[k][j]+cost[k])
				{
					int f=i,t=k;
					int loc=0;
					do
					{//遍历i->k路径,将点的序号存入s1
						s1[loc++]=t;
						t=pre[f][t];
					}while(f!=t);
					s1[loc]=-1;
					int F=i,T=j;
					loc=0;
					do
					{//遍历i->j路径,将点的序号存入s2
						s2[loc++]=T;
						T=pre[F][T];
					}while(F!=T);
					s2[loc]=-1;
					//判断字典序,是就更新路径,否则保留原来的路径
					if(intcmp(s1,s2)>0)
					{
						int p,q;
						p=k;q=j;
						do
						{
							pre[i][q]=pre[p][q];
							q=pre[p][q];
						}while(q!=p);
					}
				}
			}
	for(i=1;i<=n;i++)
		for(j=1;j<=n;j++)
			if(g[i][j]==inf)
				g[i][j]=-1;
}
void print_ans(int a,int b)
{
	printf("From %d to %d :\n",a,b);
	printf("Path: ");
	int i=a,j=b;
	while(i!=j)
	{
		sta.push(j);
		j=pre[i][j];
	}
	printf("%d", i);
	while(!sta.empty())
	{
		printf("-->%d",sta.top());
		sta.pop();
	}
	printf("\nTotal cost : %d\n",g[a][b]);
	printf("\n");
}
int main()
{
	int i,j;
	int m;
	while(scanf("%d",&n)!=EOF)
	{
		for(i=1;i<=n;i++)
			for(j=1;j<=n;j++)
				scanf("%d",&g[i][j]);
		for(i=1;i<=n;i++)
			scanf("%d",&cost[i]);
		floyed();
		scanf("%d",&m);
		int a,b;
		while(m--)
		{
			scanf("%d%d",&a,&b);
			print_ans(a,b);
		}
	}
	return 0;
}        



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
孪生素数是指两个素数之间的差为2的素数对。通过筛选法可以找出给定素数范围内的所有孪生素数的组数。 在引用的代码中,使用了递归筛选法来解决孪生素数问题。该程序首先使用循环将素数的倍数标记为非素数,然后再遍历素数数组,找出相邻素数之间差为2的素数对,并统计总数。 具体实现过程如下: 1. 定义一个数组a[N,用来标记数字是否为素数,其中N为素数范围的上限。 2. 初始化数组a,将0和1标记为非素数。 3. 输入要查询的孪生素数的个数n。 4. 循环n次,每次读入一个要查询的素数范围num。 5. 使用两层循环,外层循环从2遍历到num/2,内层循环从i的平方开始,将素数的倍数标记为非素数。 6. 再次循环遍历素数数组,找出相邻素数之间差为2的素数对,并统计总数。 7. 输出总数。 至此,我们可以使用这个筛选法的程序来解决孪生素数问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [python用递归筛选法求N以内的孪生质数(孪生素数)](https://blog.csdn.net/weixin_39734646/article/details/110990629)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [NYOJ-26 孪生素数问题](https://blog.csdn.net/memoryofyck/article/details/52059096)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值