1 条题解

  • 1
    @ 2023-12-17 17:13:20

    这道题思考不难,但比较考察代码能力。打了一个小时,调了三个小时👀️。

    第一步:需要计算出另一个城市的坐标,用两点坐标公式加以变形即可。

    第二步:导入各种的边,注意是无向图,要考虑双向。

    第三步:spfa或dijkstra计算最短路即可(好像floyd也可以)

    剩下的看代码吧。

    #include<bits/stdc++.h>
    using namespace std;
    #define p pair<int, int>  //这里我用pair把横坐标和纵坐标绑在一起 
    #define s(n) scanf("%d",&n);
    int s,t,a,b,n,cnt = 1;
    
    struct city{
    	p cs[5];
    	int tt;
    }c[110];
    
    struct edge{
    	p begin,end;
    	double data;
    	int next;
    }edges[200010];
    
    map<p, int> head; // 使pair与int相对应 这里用map来解决 map用法很像list 
    
    inline void init(p bb, p ee, double dd){
    	edges[cnt].begin = bb;
    	edges[cnt].end = ee;
    	edges[cnt].data = dd;
    	edges[cnt].next = head[bb];
    	head[bb] = cnt++;
    }
    
    inline void cinit(struct city *cc){ //读入城市 
    	s(cc->cs[1].first);s(cc->cs[1].second);
    	s(cc->cs[2].first);s(cc->cs[2].second);
    	s(cc->cs[3].first);s(cc->cs[3].second);
    	s(cc->tt);
    	//计算剩下一个城市的坐标 
    	double tri1 = pow(cc->cs[1].first - cc->cs[2].first, 2) + pow(cc->cs[1].second - cc->cs[2].second, 2);
    	double tri2 = pow(cc->cs[2].first - cc->cs[3].first, 2) + pow(cc->cs[2].second - cc->cs[3].second, 2);
    	double tri3 = pow(cc->cs[1].first - cc->cs[3].first, 2) + pow(cc->cs[1].second - cc->cs[3].second, 2);
    	if(tri1 > tri2 && tri1 > tri3){
    		cc->cs[4].first = cc->cs[1].first + cc->cs[2].first - cc->cs[3].first;
    		cc->cs[4].second = cc->cs[1].second + cc->cs[2].second - cc->cs[3].second;
    	}
    	else{
    		if(tri2 > tri1 && tri2 > tri3){
    			cc->cs[4].first = cc->cs[2].first + cc->cs[3].first - cc->cs[1].first;
    			cc->cs[4].second = cc->cs[2].second + cc->cs[3].second - cc->cs[1].second;
    		}
    		else{
    			cc->cs[4].first = cc->cs[1].first + cc->cs[3].first - cc->cs[2].first;
    			cc->cs[4].second = cc->cs[1].second + cc->cs[3].second - cc->cs[2].second;
    		}
    	}
    	// 导入铁路边 (构图)
    	for(int i=1;i<=4;i++)  //要先将head初始化一下 
    		head[cc->cs[i]] = -1;
    	for(int i=1;i<=4;i++){ //每个城市都要加3条边,所以双向边就包含在内了。 
    		for(int j=1;j<=4;j++){
    			double dt = cc->tt * sqrt( pow(cc->cs[i].first - cc->cs[j].first, 2) + pow(cc->cs[i].second - cc->cs[j].second, 2) );
    			if(i != j){
    				init(cc->cs[i], cc->cs[j], dt);
    			}
    		}
    	}
    }
    
    queue<p> q;
    map<p, double> dis,flag; 
    double ans = INT_MAX;
    
    inline void spfa(){  //正经的spfa,我用的堆优化 
    	for(int i=1;i<=4;i++){
    		for(int z=1;z<=s;z++){  //初始化dis和flag 
    			for(int j=1;j<=4;j++){
    				dis[c[z].cs[j]] = 1061109567;
    				flag[c[z].cs[j]] = 0;
    			}
    		}
    		dis[c[a].cs[i]] = 0;
    		flag[c[a].cs[i]] = 1;
    		q.push(c[a].cs[i]);
    		while(!q.empty()){
    			p f = q.front();
    			for(int j = head[f]; ~j; j = edges[j].next){
    				p ec = edges[j].end;
    				if(dis[ec] > dis[f] + edges[j].data){
    					dis[ec] = dis[f] + edges[j].data;
    					if(!flag[ec]){
    						q.push(ec);
    						flag[ec] = 1;
    					}
    				}
    			}
    			q.pop();
    			flag[f] = 0;
    		}
    		for(int j=1;j<=4;j++)
    			ans = min(ans, dis[c[b].cs[j]]); //计算最小值 
    	}
    }
    
    int main(){
    	s(n);
    	for(int i=0;i<n;i++){
    		s(s);s(t);s(a);s(b);
    		for(int i=1;i<=s;i++){
    			cinit(&c[i]);
    		}
    		for(int i=1;i<=s;i++){ //导入飞行航线,构图 
    			for(int z=1;z<=4;z++){
    				for(int j=1;j<=s;j++){
    					if(i >= j) continue; //这个很重要,因为我后边加了双向边,所以必须每个城市只考虑一次,就是1->2,1->3,2->3,然后结束 
    					for(int v=1;v<=4;v++){
    						double dt = sqrt( pow(c[i].cs[z].first - c[j].cs[v].first, 2) + pow(c[i].cs[z].second - c[j].cs[v].second, 2) );
    						init(c[i].cs[z], c[j].cs[v], dt*t);
    						init(c[j].cs[v], c[i].cs[z], dt*t);
    					}
    				}
    			}
    		}
    		spfa();
    		printf("%.1f\n",ans);
    	}
    	return 0;
    }
    
    • 1

    [NOIP2001 提高组] Car 的旅行路线

    信息

    ID
    1746
    时间
    1000ms
    内存
    256MiB
    难度
    5
    标签
    递交数
    23
    已通过
    13
    上传者