Help Jimmy POJ - 1661(dp/最短路)

“Help Jimmy” 是在下图所示的场景上完成的游戏。

场景中包括多个长度和高度各不相同的平台。地面是最低的平台,高度为零,长度无限。

Jimmy老鼠在时刻0从高于所有平台的某处开始下落,它的下落速度始终为1米/秒。当Jimmy落到某个平台上时,游戏者选择让它向左还是向右跑,它跑动的速度也是1米/秒。当Jimmy跑到平台的边缘时,开始继续下落。Jimmy每次下落的高度不能超过MAX米,不然就会摔死,游戏也会结束。

设计一个程序,计算Jimmy到底地面时可能的最早时间。
Input
第一行是测试数据的组数t(0 <= t <= 20)。每组测试数据的第一行是四个整数N,X,Y,MAX,用空格分隔。N是平台的数目(不包括地面),X和Y是Jimmy开始下落的位置的横竖坐标,MAX是一次下落的最大高度。接下来的N行每行描述一个平台,包括三个整数,X1[i],X2[i]和H[i]。H[i]表示平台的高度,X1[i]和X2[i]表示平台左右端点的横坐标。1 <= N <= 1000,-20000 <= X, X1[i], X2[i] <= 20000,0 < H[i] < Y <= 20000(i = 1…N)。所有坐标的单位都是米。

Jimmy的大小和平台的厚度均忽略不计。如果Jimmy恰好落在某个平台的边缘,被视为落在平台上。所有的平台均不重叠或相连。测试数据保证问题一定有解。
Output
对输入的每组测试数据,输出一个整数,Jimmy到底地面时可能的最早时间。
Sample Input
1
3 8 17 20
0 10 8
0 10 13
4 14 3
Sample Output
23

思路:
对于每个平板从左和从右跳都只有一个对应的平板(或者地面)。
跳下去可以往左也可以往右,
定义状态dp[i][0/1]代表第i个平板跳下去往左(右)走的最小花费。
子状态就是dp[j][0/1] + val。val代表从i到j平板再跳下去的距离。

同理也可以按照每个平板左右位置为节点建图,结果就是0节点到最后节点的最短路。

DP

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int INF = 0x3f3f3f3f;
const int maxn = 2005;

struct Node
{
    int l,r,h;
}a[maxn];
int dp[maxn][2];

int cmp(Node a,Node b)
{
    return a.h < b.h;
}

int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        int n,x,y,mx;scanf("%d%d%d%d",&n,&x,&y,&mx);
        a[0].l = x;a[0].r = x;a[0].h = y;
        for(int i = 1;i <= n;i++)
        {
            scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].h);
        }
        a[n + 1].l = -20005;a[n + 1].r = 20005;a[n + 1].h = 0;
        sort(a,a + 2 + n,cmp);
        
        for(int i = 1;i <= n + 1;i++)
        {
            int j;
            for(j = i - 1;j >= 0;j--)
            {
                if(a[j].l <= a[i].l && a[j].r >= a[i].l)break;
            }
            if(j > 0)
            {
                if(a[i].h - a[j].h > mx)
                {
                    dp[i][0] = INF;
                }
                else
                {
                    int t1 = a[i].h - a[j].h + a[i].l - a[j].l + dp[j][0];
                    int t2 = a[i].h - a[j].h + a[j].r - a[i].l + dp[j][1];
                    dp[i][0] = min(t1,t2);
                }
            }
            else
            {
                if(a[i].h > mx)dp[i][0] = INF;
                else dp[i][0] = a[i].h;
            }
            
            for(j = i - 1;j >= 0;j--)
            {
                if(a[j].l <= a[i].r && a[j].r >= a[i].r)break;
            }
            if(j > 0)
            {
                if(a[i].h - a[j].h > mx)dp[i][1] = INF;
                else
                {
                    int t1 = a[i].h - a[j].h + a[i].r - a[j].l + dp[j][0];
                    int t2 = a[i].h - a[j].h + a[j].r - a[i].r + dp[j][1];
                    dp[i][1] = min(t1,t2);
                }
            }
            else
            {
                if(a[i].h > mx)dp[i][1] = INF;
                else
                {
                    dp[i][1] = a[i].h;
                }
            }
        }
        
        printf("%d\n",min(dp[n + 1][1],dp[n + 1][0]));
    }
    return 0;
}

dijkstra

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;

const int INF = 0x3f3f3f3f;
const int maxn = 4005;

struct Line
{
    int l,r,h;
}line[maxn];

struct Edge
{
    int to,nex,val;
}edges[maxn];
int head[maxn],tot;
int dis[maxn],vis[maxn];
int n,x,y,mx;

struct Node
{
    int x;
    int dis;
    Node(){}
    Node(int x,int dis):x(x),dis(dis){}
    bool operator < (const Node &rhs)const
    {
        return dis > rhs.dis;
    }
};

int L(int i){return i * 2 - 1;}
int R(int i){return i * 2;}

int cmp(Line a,Line b)
{
    return a.h < b.h;
}

void init()
{
    memset(head,0,sizeof(head));
    tot = 0;
}

void add(int x,int y,int z)
{
    edges[++tot].to = y;
    edges[tot].nex = head[x];
    edges[tot].val = z;
    head[x] = tot;
}

void dijkstra(int s)
{
    
    memset(dis,INF,sizeof(dis));
    memset(vis,0,sizeof(vis));
    priority_queue<Node>q;
    q.push(Node(s,0));
    dis[s] = 0;
    while(!q.empty())
    {
        Node now = q.top();q.pop();
        int x = now.x;vis[x] = 1;
        
        if(x == 2 * n + 1)
        {
            printf("%d\n",now.dis);
            break;
        }
        
        for(int i = head[x];i;i = edges[i].nex)
        {
            int v = edges[i].to;
            if(vis[v])continue;
            if(dis[v] > dis[x] + edges[i].val)
            {
                dis[v] = dis[x] + edges[i].val;
                q.push(Node(v,dis[v]));
            }
        }
    }
}

void solve()
{
    scanf("%d%d%d%d",&n,&x,&y,&mx);
    for(int i = 1;i <= n;i++)
    {
        scanf("%d%d%d",&line[i].l,&line[i].r,&line[i].h);
    }
    sort(line + 1,line + 1 + n,cmp);
    for(int i = 1;i <= n;i++)
    {
        int cnt1 = 0,cnt2 = 0;
        for(int j = i - 1;j >= 1;j--)
        {
            if(line[j].l <= line[i].l && line[j].r >= line[i].l)
            {
                cnt1++;
                if(cnt1 == 1 && line[i].h - line[j].h <= mx)
                {
                    int w = line[i].h - line[j].h + line[i].l - line[j].l;
                    add(L(j),L(i),w);
                    
                    w = line[i].h - line[j].h + line[j].r - line[i].l;
                    add(R(j),L(i),w);
                }
            }
            if(line[j].l <= line[i].r && line[j].r >= line[i].r)
            {
                cnt2++;
                if(cnt2 == 1 && line[i].h - line[j].h <= mx)
                {
                    int w = line[i].h - line[j].h + line[i].r - line[j].l;
                    add(L(j),R(i),w);
                    
                    w = line[i].h - line[j].h + line[j].r - line[i].r;
                    add(R(j),R(i),w);
                }
            }
            if(cnt1 && cnt2)break;
        }
        if(cnt1 == 0 && line[i].h <= mx)
        {
            add(0,L(i),line[i].h);
        }
        if(cnt2 == 0 && line[i].h <= mx)
        {
            add(0,R(i),line[i].h);
        }
    }
    
    int cnt = 0;
    for(int i = n;i >= 1;i--)
    {
        if(line[i].l <= x && line[i].r >= x && y - line[i].h <= mx)
        {
            cnt++;
            
            int w = y - line[i].h + x - line[i].l;
            add(L(i),2 * n + 1,w);
            w = y - line[i].h + line[i].r - x;
            add(R(i),2 * n + 1,w);
            
            break;
        }
    }
    if(cnt == 0 && y <= mx)
    {
        add(0,2 * n + 1,y);
    }
}

int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        init();
        solve();
        dijkstra(0);
    }
    return 0;
}
发布了676 篇原创文章 · 获赞 18 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/tomjobs/article/details/104230342