I - Color Tunnels POJ - 1685 (动态规划)

I - Color Tunnels

 POJ - 1685 

A company producing toys has a complex system to paint its products. To obtain the desired color, the product must be painted by several colors in a specified order. A product is painted by moving through color tunnels. For each color there is at least one tunnel that paints with that color, but there may be more. The tunnels are distributed in the painting area and the product must be delivered from one tunnel to another in order to be painted with the given colors. The product is at a certain point in the production plant when painting process starts and must finally be delivered to the product warehouse. 

More formally, a finished uncolored product is at a certain given point (source point) and must be delivered to another given point (destination point) after being painted with different colors in a given order. There are several tunnels, each is assumed to be a line segment in the plain with a specific color. The colors of the tunnels are not necessarily distinct. Let < c1, c2, ..., cn > be the sequence of n colors that the product is to be painted with. The product is required to pass through tunnels < t1, t2, ... tn > such that the color of ti is ci. Note that it is possible to pass through a tunnel without being painted, so the mentioned < t1, t2, ... tn > may be in fact a subsequence of the tunnels which the product passes through. The direction in which the product passes a tunnel is not important. The goal is to find the shortest path from source to destination subject to the color constraints. The path may cross itself, or even cross a tunnel. Passing twice (or more) through a tunnel is also allowed. Note that two tunnels can cross or overlap but are different. 

Input

The input file contains several test cases. The first line of the input consists of a single integer t (between 1 and 20), the number of test cases. Following the first line is the data for t test cases. The first line of each test case contains four real numbers xs, ys, xt, yt which are x and y coordinates of the source and destination respectively. The second line of the test case contains the color sequence: the first number is the length of the sequence (between 1 and 30), and the rest of the line is the sequence itself. Each color in the sequence is an integer in the range 1...100. The third line contains a single integer n in the range 1...60 which is the number of tunnels followed by n lines each containing five numbers. The first two numbers are the x and y coordinates of one end of the tunnel. The third and fourth numbers are the x and y coordinates of the other end. Coordinates are real numbers. The fifth number is an integer in the range 1...100

Output

The output file must have t lines, each containing the minimum length of a path from source to destination subject to the constraints of the problem. The length will be compared to optimal length within a precision of three digits after decimal point.

Sample Input

1
0 1.5 100 67
4 1 4 3 1
9
10 10 20 20 1
10 15 20.5 35.333 3
30 15 14.55 12.5 1
40 30 44 33 1
29 84 33 58 4
9 39 41 115 2
75 47 37 69 4
46 26 58 25 3
73 48 27 59 3

Sample Output

240.60967918717043

题意: 从一个起点出发经过特定颜色顺序的颜色染色道(相同的染色道可以有多个),最后到一个终点,求需经过的最小距离,注意最后结果保留三位小数

思路:动态规划解法:

为方便计算,把开始点作为必须经过的染色道,染色颜色为0(非0~100都可以),同样把终点当做一个必须经过的染色道,记染色颜色为101;

到终点颜色道之前,每染色到一个颜色col[i],就有1个或多个染色道可以染色成颜色col[i],我们无法判断计算哪个符合染色的染色道可以完成染色的最短距离,因为即使到这个染色道某端(穿过染色道出来后的一端)的距离是到符合染色的各个染色道各个端点中最短的,但有可能这个端点离下一个染色道或是终点很远,所以最好的做法保存从起点到符合染色的各个染色道各个端点的最短距离。

now[j][0]=min{pre[k][0]+dis(vec[val][1][k],vec[id][0][j])+len,pre[k][1]+dis(vec[val][0][k],vec[id][0][j])+len}

now[j][0]表示染色第i个颜色时通过符合染色的第j个染色道左端进去的最短距离,这个最短距离需要从上一次符合染色的各染色道k(上一次从左边染色道出来或从右边染色道出来)到符合当前染色的第j个染色道左端进去的最短距离。len是符合染色的第j个染色道的长度。

now[j][1]=min{}pre[k][0]+dis(vec[val][1][k],vec[id][1][j])+len,pre[k][1]+dis(vec[val][0][k],vec[id][1][j])+len}

now[j][1]表示染色第i个颜色时通过符合染色的第j个染色道右端进去的最短距离

#include<cstdio>
#include<stack>
#include<set>
#include<vector>
#include<queue>
#include<algorithm>
#include<cstring>
#include<string>
#include<map>
#include<iostream>
#include<cmath>
using namespace std;
#define inf 0x3f3f3f3f
typedef long long ll;
const int N=110;
const int nmax = 1010;
const double esp = 1e-8;
const double PI=3.1415926;
struct node
{
    double x,y;
} ;
int col[N];
double dis(node p,node q)
{
    return sqrt((p.x-q.x)*(p.x-q.x)+(p.y-q.y)*(p.y-q.y));
}
double mymin(double x,double y)
{
    if(x-y<esp)
        return x;
    return y;
}
double pre[nmax][2],now[nmax][2];
int main()
{
    int t,cn,tn;
    int co;
    scanf("%d",&t);
    while(t--)
    {
//vector容器保存染色道端点,vec[i][0]表示染颜色i的左端点,vec[i][1]表示染颜色i的右端点
        vector<node>vec[nmax][2];
        node l,r;
        double sx,sy,tx,ty;
        scanf("%lf%lf%lf%lf",&sx,&sy,&tx,&ty);
        //把开始点作为必须经过的一个染色道,染色为0
        l.x=r.x=sx;
        l.y=r.y=sy;
        col[0]=0;
        vec[0][0].push_back(l);
        vec[0][1].push_back(r);
        scanf("%d",&cn);
        for(int i=1; i<=cn; i++)
            scanf("%d",&col[i]);
        
        scanf("%d",&tn);
        for(int i=1; i<=tn; i++)
        {
            scanf("%lf%lf%lf%lf%d",&l.x,&l.y,&r.x,&r.y,&co);
            vec[co][0].push_back(l);
            vec[co][1].push_back(r);
        }
        //把终点点作为必须经过的一个染色道,染色为0
        col[cn+1]=101;
        l.x=r.x=tx;
        l.y=r.y=ty;
        vec[101][0].push_back(l);
        vec[101][1].push_back(r);
        pre[0][0]=pre[0][1]=0.0;
        for(int i=1; i<=cn+1; i++)
        {
            int id=col[i];
            for(int j=0; j<vec[id][0].size(); j++)
            {
                  //初始化通过第j个可以染色为col[i]的管道,且从管道左边进去的值为无穷大
                now[j][0]=11111111.1;  
                //初始化通过第j个可以染色为col[i]的管道,且从管道右边进去的值为无穷大
                now[j][1]=11111111.1;
                int val=col[i-1];
                double len=dis(vec[id][0][j],vec[id][1][j]);
                for(int k=0; k<vec[val][0].size(); k++)  
                {//遍历从上一次染色经过的每一条符合染色经过的最小距离的染色道到当前符合染色的第j个染色道的最小距离
                    now[j][0]=mymin(now[j][0],mymin(pre[k][0]+dis(vec[val][1][k],vec[id][0][j])+len,pre[k][1]+dis(vec[val][0][k],vec[id][0][j])+len));
                    now[j][1]=mymin(now[j][1],mymin(pre[k][0]+dis(vec[val][1][k],vec[id][1][j])+len,pre[k][1]+dis(vec[val][0][k],vec[id][1][j])+len));
                }
            }
            for(int j=0; j<vec[id][0].size(); j++)
            {
                  //保存到符合染色为col[i]的染色道最小距离
                pre[j][0]=now[j][0];
                pre[j][1]=now[j][1];
            }
        }
        double minl=mymin(now[0][0],now[0][1]);  //取最后一次(即终点)从左侧和从右侧进去的最小值
        printf("%.3lf\n",minl);
    }
    return 0;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值