洛谷 P1027 CODE[VS] 1041 [NOIP2001 T4] Car的旅行路线

99 篇文章 0 订阅
59 篇文章 0 订阅

题目描述

又到暑假了,住在城市A的Car想和朋友一起去城市B旅游。她知道每个城市都有四个飞机场,分别位于一个矩形的四个顶点上,同一个城市中两个机场之间有一条笔直的高速铁路,第I个城市中高速铁路了的单位里程价格为Ti,任意两个不同城市的机场之间均有航线,所有航线单位里程的价格均为t。

图例(从上而下)

机场 高速铁路

飞机航线

  注意:图中并没有

标出所有的铁路与航线。

那么Car应如何安排到城市B的路线才能尽可能的节省花费呢?她发现这并不是一个简单的问题,于是她来向你请教。

找出一条从城市A到B的旅游路线,出发和到达城市中的机场可以任意选取,要求总的花费最少。

输入输出格式

输入格式:

第一行为一个正整数n(0<=n<=10),表示有n组测试数据。

每组的第一行有四个正整数s,t,A,B。

S(0<S<=100)表示城市的个数,t表示飞机单位里程的价格,A,B分别为城市A,B的序号,(1<=A,B<=S)。

接下来有S行,其中第I行均有7个正整数xi1,yi1,xi2,yi2,xi3,yi3,Ti,这当中的(xi1,yi1),(xi2,yi2),(xi3,yi3)分别是第I个城市中任意三个机场的坐标,T I为第I个城市高速铁路单位里程的价格。

输出格式:

共有n行,每行一个数据对应测试数据。 保留一位小数

输入输出样例

输入样例#1:
1
3 10 1 3
1 1 1 3 3 1 30
2 5 7 4 5 2 1
8 6 8 8 11 6 3
输出样例#1:
47.5












~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

SPFA+数论(图论?)~

写代码一节课,检查三节课……double和int一定要分清啊啊啊啊!

SPFA部分就不说了,主要是给出三个点求第四个点和点之间建边比较麻烦,用到了向量,具体的不好说,看代码吧~


#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<queue>
using namespace std;

int n,s,t,A,B,fi[401],w[340001],ne[340001],cnt,x[5][401],y[5][401],val;
double v[340001],dis[401],minn;
bool b[401];
queue<int> q;

void add(int u,int vv,double val1)
{
	w[++cnt]=vv;v[cnt]=val1;ne[cnt]=fi[u];fi[u]=cnt;
}

double cal(double x1,double y1,double x2,double y2)
{
	return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}

double cal2(int x1,int y1,int x2,int y2)
{
	return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);
}

void getn(int u)
{
	double k[4]={0,cal2(x[1][u],y[1][u],x[2][u],y[2][u]),
	               cal2(x[2][u],y[2][u],x[3][u],y[3][u]),
				   cal2(x[3][u],y[3][u],x[1][u],y[1][u])},tot=k[1]+k[2]+k[3];
	int fre,num[3]={0};
	for(int i=1;i<=3;i++)
	  if(k[i]*2==tot) fre=(i==1 ? 3:i-1);
	  else num[++num[0]]=(i==1 ? 3:i-1);
	x[4][u]=x[num[1]][u]+x[num[2]][u]-x[fre][u];
	y[4][u]=y[num[1]][u]+y[num[2]][u]-y[fre][u];
}

int main()
{
	scanf("%d",&n);
	while(n--)
	{
		scanf("%d%d%d%d",&s,&t,&A,&B);minn=999999999;
		memset(fi,0,sizeof(fi));cnt=0;
		for(int k=1;k<=s;k++)
		{
			scanf("%d%d%d%d%d%d%d",&x[1][k],&y[1][k],&x[2][k],&y[2][k],&x[3][k],&y[3][k],&val);
			getn(k);
			for(int i=1;i<=3;i++)
			  for(int j=i+1;j<=4;j++)
			  {
			  	double kkz=cal(x[i][k],y[i][k],x[j][k],y[j][k])*(double)val;
			  	add(4*k+i-4,4*k+j-4,kkz);add(4*k+j-4,4*k+i-4,kkz);
			  }
		}
		for(int k1=1;k1<s;k1++)
		  for(int k2=k1+1;k2<=s;k2++)
		    for(int i=1;i<=4;i++)
		  	  for(int j=1;j<=4;j++)
		  	  {
		  	  	double kkz=cal(x[i][k1],y[i][k1],x[j][k2],y[j][k2])*(double)t;
		  	  	add(4*k1-4+i,4*k2-4+j,kkz);add(4*k2-4+j,4*k1-4+i,kkz);
			  }
		for(int i=1;i<=4;i++)
		{
			memset(dis,127,sizeof(dis));
			q.push(A*4-4+i);b[A*4-4+i]=1;dis[A*4-4+i]=0;
			while(!q.empty())
			{
				int k=q.front();q.pop();b[k]=0;
				for(int j=fi[k];j;j=ne[j])
				  if(dis[w[j]]>dis[k]+v[j])
				  {
					dis[w[j]]=dis[k]+v[j];
					if(!b[w[j]])
					{
						b[w[j]]=1;q.push(w[j]);
					}
				  }
			}
			for(int j=1;j<=4;j++)
			  if(dis[B*4-4+j]<minn) minn=dis[B*4-4+j];
		}
		printf("%.1lf\n",minn);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值