Asia Regional Contest, Tokyo, 2014 Shopping

本文介绍了一种解决特定逛街购物场景下最短路径问题的算法。在一个有N个店铺的直线上,根据一定的购物顺序限制,计算从入口到出口所需的最小行走距离。通过将可能重叠的回头走区间合并,确保计算出的路径既满足购物顺序要求又达到最短。

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

题目链接:点击打开链接

 

Description

Your friend will enjoy shopping. She will walk through a mall along a straight street, where N individual shops (numbered from 1 to N) are aligned at regular intervals. Each shop has one door and is located at the one side of the street. The distances between the doors of the adjacent shops are the same length, i.e. a unit length. Starting shopping at the entrance of the mall, she visits shops in order to purchase goods. She has to go to the exit of the mall after shopping. She requires some restrictions on visiting order of shops. Each of the restrictions indicates that she shall visit a shop before visiting another shop. For example, when she wants to buy a nice dress before choosing heels, she shall visit a boutique before visiting a shoe store. When the boutique is farther than the shoe store, she must pass the shoe store before visiting the boutique, and go back to the shoe store after visiting the boutique. If only the order of the visiting shops satisfies all the restrictions, she can visit other shops in any order she likes. Write a program to determine the minimum required walking length for her to move from the entrance to the exit. Assume that the position of the door of the shop numbered k is k units far from the entrance, where the position of the exit is N + 1 units far from the entrance.

Input

The input consists of several tests case. N m c1 d1 … cm dm For each test, the first line contains two integers N and m, where N (1 ≤ N ≤ 1000) is the number of shops, and m (0 ≤ m ≤ 500) is the number of restrictions. Each of the next m lines contains two integers ci and di (1 ≤ ci < di ≤ N) indicating the i-th restriction on the visiting order, where she must visit the shop numbered ci after she visits the shop numbered di (i = 1, . . . , m). Therearenopairofjandkthatsatisfycj =ck anddj =dk.

Output

Output the minimum required walking length for her to move from the entrance to the exit. You should omit the length of her walk in the insides of shops.

Sample Input

10 3
3 7
8 9
2 5
10 3
8 9
6 7
2 4
10 0
10 6
6 7
4 5
2 5
6 9
3 5
6 8
1000 8
3 4
6 1000
5 1000
7 1000
8 1000
4 1000
9 1000
1 2

Sample Output

23
19
11
23
2997
Hint

Source

Asia Regional Contest, Tokyo, 2014

题意

一个朋友要逛街,这条街有N个店,每个店要买些东西,但是有些店要在另外的一个店之前逛。输入店N个,m个限制,后面跟m行,每行前面的在后面的店之后逛。要求求出走的最小距离。

思路

开始以为是将所有的限制算出最大的,走到最大的走回最小的,发现不对。

其实是这样的,对于每个限制,如果小的店在大的店之前逛不用考虑,直接走;对于大的比小的先逛,就需要往回走。画一个图,将后面的先逛的限制条件所需要往回走的区间画出,将重叠的合并为一个区间,走到合并的区间的终点再往回走,这样的话原先需要走多遍的重叠的区域只需要往回走一遍,而并不需要往回走的区域就只正向走了一次。

代码

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>

using namespace std;  

struct Node{
    int start;  
    int end;  
}node[1000];

bool cmp(Node a, Node b){
    return (a.start < b.start) || (a.start==b.start && a.end <= b.end);  
}

int main(){
    //freopen("2.txt", "r", stdin);
    int N, M;  
    int numa, numb;  
    while(~scanf("%d%d", &N, &M)){  //输入总的数量和限制个数 
        int number = 0;  
        memset(node,0,sizeof(node));  
        for(int i=1;i<=M;i++){
            scanf("%d%d", &numa, &numb);  
            if(numa < numb){  //只有当先走后面的再走前面的才要考虑 
                node[number].start=numa;  
                node[number++].end=numb;  
            }
        }
        sort(node,node+number,cmp);  //进行排序 
        int left=node[0].start, right=node[0].end;  //首先从第一个设置起 
        int label=0;  //label先置为0 
        for(int i=1;i<number;i++){  //合并所有的节点 
            if(right >= node[i].start){  //存在重叠,合并 
                right=max(right,node[i].end);  //有可能后面的起点大,终点反而比较小 
                node[i].start=node[i].end=0;  
                if(i == number-1){  //最后一个节点要特殊处理 
                    node[label].end=right; 
                }
            }
            else{  //合并后的节点放入label,开始新一个的节点合并 
                node[label].end=right;  
                label=i;    
                right=node[i].end;  
            }
        }
        //node[label].end=right;  
        int ans=N+1;  
        for(int i=0;i<number;i++){   
            if(node[i].start != 0){  //存放了节点的节点就是要计算的 
                ans += 2*(node[i].end-node[i].start);  //这块区域总共要走三遍,此处再算两遍 
            }
        }
        printf("%d\n", ans);  
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值