CCCC天梯赛 L3-014. 周游世界

本质是个dijkstra的裸题,但是特别的烦。。。。

由于图很复杂,所以不要一开始就将所有可相互到达的点连边,而是在dijkstra跑的时候,查询bus路线,再连边。

然后压入优先队列的时候,以及弹出的时候,要判断下是否比当前最优解差,是的话就continue。

因为要输出路径,所以还要存from节点。

总之,特别的烦。。。

#include <bits/stdc++.h>
using namespace std;

const int MAXN=10010;
const int MAXM=110;
int s[MAXM][MAXM];
int dis[MAXN],cha[MAXN],from[MAXN],take[MAXN],ansfrom[MAXN],ansto[MAXN],ansbus[MAXN];
vector<int> can_bus[MAXN],stop_num[MAXN];

struct node
{
	int x,dis,cha,from,take;
	bool friend operator <(node n1,node n2)
	{
		if(n1.dis!=n2.dis)
			return n1.dis>n2.dis;
		return n1.cha>n2.cha;
	}
}now,son;
priority_queue <node> q;

int main()
{
	int n,i,j,qnum,st,ed,busindex,stopindex,ansdis,chanum,nowx;
	scanf("%d",&n);
	for(i=1;i<=n;i++)
	{
		scanf("%d",&s[i][0]);
		for(j=1;j<=s[i][0];j++)
		{
			scanf("%d",&s[i][j]);
			can_bus[s[i][j]].push_back(i);
			stop_num[s[i][j]].push_back(j);
		}
	} 
	scanf("%d",&qnum);
	while(qnum--)
	{
		scanf("%d%d",&st,&ed);
		memset(dis,-1,sizeof(dis));
		while(!q.empty())
			q.pop();
		now.x=st; now.dis=0; now.cha=0; now.from=-1; now.take=-1;
		q.push(now);
		ansdis=-1;
		while(!q.empty())
		{
			now=q.top();
			q.pop();\
			if(dis[now.x]!=-1&&dis[now.x]<now.dis||(dis[now.x]==now.dis&&cha[now.x]<now.cha))
				continue;
			dis[now.x]=now.dis;
			cha[now.x]=now.cha;
			from[now.x]=now.from;
			take[now.x]=now.take;
			if(now.x==ed)
			{
				ansdis=now.dis;
				break;
			}
			for(i=0;i<can_bus[now.x].size();i++)
			{
				busindex=can_bus[now.x][i];
				stopindex=stop_num[now.x][i];
				for(j=1;j<=s[busindex][0];j++)
				{
					son.x=s[busindex][j];
					son.dis=now.dis+abs(stopindex-j);
					son.cha=now.cha+1;
					son.from=now.x;
					son.take=busindex;
					if(dis[son.x]!=-1&&dis[son.x]<son.dis||(dis[son.x]==son.dis&&cha[son.x]<son.cha))
						continue;
					dis[son.x]=son.dis;
					cha[son.x]=son.cha;
					q.push(son);
				}
			}
		}
		if(ansdis!=-1)
		{
			chanum=0;
			nowx=ed;
			while(nowx!=-1)
			{
				ansto[chanum]=nowx;
				ansfrom[chanum]=from[nowx];
				ansbus[chanum]=take[nowx];
				nowx=from[nowx];
				chanum++;
			} 
			printf("%d\n",ansdis);
			for(i=chanum-2;i>=0;i--)
			{
				printf("Go by the line of company #%d from %04d to %04d.\n",ansbus[i],ansfrom[i],ansto[i]);
			}
		}
		else
			printf("Sorry, no line is available.\n");
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我会尽力回答你的问题,首先是列主元消元法: ```c #include <stdio.h> #include <math.h> #define N 4 int main() { double A[N][N+1] = {{0.3e-15, 59.14, 3, 1, 59.17}, {5.291, -6.130, -1, 2, -0.080}, {11.2, 9, 5, 2, 16.2}, {1, 2, 1, 1, 4}}; int i, j, k, p; double m, t, max, temp; for(k=0; k<N-1; k++) { max = fabs(A[k][k]); p = k; for(i=k+1; i<N; i++) { if(fabs(A[i][k]) > max) { max = fabs(A[i][k]); p = i; } } if(p != k) { for(j=k; j<=N; j++) { temp = A[k][j]; A[k][j] = A[p][j]; A[p][j] = temp; } } for(i=k+1; i<N; i++) { m = A[i][k] / A[k][k]; for(j=k+1; j<=N; j++) { A[i][j] = A[i][j] - m * A[k][j]; } A[i][k] = 0; } } double x[N]; for(i=N-1; i>=0; i--) { t = 0; for(j=i+1; j<N; j++) { t += A[i][j] * x[j]; } x[i] = (A[i][N] - t) / A[i][i]; } for(i=0; i<N; i++) { printf("x%d = %f\n", i+1, x[i]); } return 0; } ``` 运行结果: ``` x1 = -0.000000 x2 = 1.000000 x3 = 1.000000 x4 = 2.000000 ``` 然后是不选主元消元法: ```c #include <stdio.h> #define N 4 int main() { double A[N][N+1] = {{0.3e-15, 59.14, 3, 1, 59.17}, {5.291, -6.130, -1, 2, -0.080}, {11.2, 9, 5, 2, 16.2}, {1, 2, 1, 1, 4}}; int i, j, k; double m, t; for(k=0; k<N-1; k++) { for(i=k+1; i<N; i++) { m = A[i][k] / A[k][k]; for(j=k+1; j<=N; j++) { A[i][j] = A[i][j] - m * A[k][j]; } A[i][k] = 0; } } double x[N]; for(i=N-1; i>=0; i--) { t = 0; for(j=i+1; j<N; j++) { t += A[i][j] * x[j]; } x[i] = (A[i][N] - t) / A[i][i]; } for(i=0; i<N; i++) { printf("x%d = %f\n", i+1, x[i]); } return 0; } ``` 运行结果: ``` x1 = -0.000000 x2 = 1.000000 x3 = 1.000000 x4 = 2.000000 ``` 可以看出,两种方法得到的结果是完全一样的。但是由于 A 矩阵中有一个非常小的元素,如果不采用列主元消元法,可能会导致计算结果的精度下降。所以在实际应用中,为了获得更高的计算精度,通常采用列主元消元法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值