zoukankan      html  css  js  c++  java
  • hdu 3440 House Man

    https://vjudge.net/problem/HDU-3440

    题意:

    一个超人,他可以一个从一栋楼跳到另一栋楼。有一天,他为了加强技能,准备跳一系列的楼,他每次都从低的楼,跳到高的楼。他从最低的楼开始跳,但是他跳的水平距离是有限制的。

    但是因为他是超人,所以他可以任意移动楼,而且他想他开始跳的楼与最后跳到的楼的距离最大。

    他移动楼的时候有某些限制:

    1.移动之后的楼的排列顺序必须与输入的顺序相同。

    2.必须满足水平跳跃的距离的限制。

    求这个最大距离,如果跳不到的话,输出-1。

    思路:

    首先,超人跳的每栋楼的是按照高度递增的顺序来的,比如说i,j是高度相邻的两栋楼,那么两栋楼之间的距离肯定得满足|xi - xj| <= d(限制),然后因为每栋楼之间的距离肯定是大于等于1的,所以Xi+1 - Xi >= 1,所以我们就可以找出一系列的不等式。我们需要通过这一系列的不等式找出加入最低的下标为u,最高的下标为v,那么就是|Xu-Xv|的最大值,这样的问题其实是一类叫做差分约束系统的问题。

    差分约束系统是由最短路的松弛条件d[v] >= d[u] + w(u,v) 得来的,假设有不等式 Xi - Xj <= len,变形得到 Xi <= Xj + len,这样就和最短路的松弛条件近似了,虽然说一个是大于等于,一个是小于等于,但是本质其实是一样的,可以看成d[i] <= d[j] + w(j,i),那么此时就可以建一条从j到i的边,然后求出目标不等式的最大值,即相当于求图中的最短路。

    为什么是最短路呢?比如有a - b <= 3 ,b - c <= 5,a - c <= 10,此时如果要求a - c的最大值,可以轻易地看出最大值是8,即是图中的a到c的最短路,而不是10,本质是求所有不等式的交集,按照差分的约束条件 <= ,那么就是求最小的那个。

    还剩一个问题就是有没有可能出现无解的情况,那就是图中出现了负环,最短路可以无穷小,此时当然就无解了,比如b - a <= -3,c - b <= 2 ,a - c <= -5,那么此时就是一个负环,此时求c - a的最小值,有c - a <= -1,c - a >= 5,此时就矛盾了,不存在最小值。

    ok,回过来看这道题,根据题中的|xi - xj| <= d,我们可以建图,去掉绝对值的方法就是边从下标小的点指向下标大的点,因为输入的楼之间是有先后顺序的,之后因为每栋楼之间的距离必须大于等于1,所以Xi+1 - Xi >= 1(上面提到了,之后跑图的话,就用spfa,因为dij无法判断途中是否存在负环,spfa判断途中是否存在负环的条件是一个点入队的次数大于了n。

    代码:

      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <vector>
      4 #include <queue>
      5 #include <algorithm>
      6 using namespace std;
      7 
      8 struct edge
      9 {
     10     int from,to;
     11     int w;
     12 
     13     edge(){};
     14     edge(int x,int y,int z)
     15     {
     16         from = x;
     17         to = y;
     18         w = z;
     19     }
     20 };
     21 
     22 struct node
     23 {
     24     int hei;
     25     int id;
     26 
     27     bool operator < (const node &rhs) const
     28     {
     29         return this -> hei < rhs.hei;
     30     }
     31 } h[1005];
     32 
     33 vector<edge> edges;
     34 vector<int> v[1005];
     35 
     36 void init(int n)
     37 {
     38     edges.clear();
     39 
     40     for (int i = 0;i <= n;i++)
     41         v[i].clear();
     42 }
     43 
     44 void adde(int from,int to,int w)
     45 {
     46     edge e = edge(from,to,w);
     47 
     48     edges.push_back(e);
     49 
     50     int sz = edges.size();
     51 
     52     v[from].push_back(sz - 1);
     53 }
     54 
     55 bool vis[1005];
     56 int d[1005];
     57 int cnt[1005];
     58 const int inf = 0x3f3f3f3f;
     59 
     60 bool spfa(int s,int n)
     61 {
     62     memset(vis,0,sizeof(vis));
     63     memset(d,inf,sizeof(d));
     64     memset(cnt,0,sizeof(cnt));
     65 
     66     vis[s] = 1;
     67     cnt[s] = 1;
     68 
     69     queue<int> q;
     70 
     71     q.push(s);
     72 
     73     d[s] = 0;
     74 
     75     while (!q.empty())
     76     {
     77         int cur = q.front();
     78         q.pop();
     79 
     80         vis[cur] = 0;
     81 
     82         for (int i = 0;i < v[cur].size();i++)
     83         {
     84             int id = v[cur][i];
     85 
     86             int to = edges[id].to;
     87 
     88             if (d[to] > d[cur] + edges[id].w)
     89             {
     90                 d[to] = d[cur] + edges[id].w;
     91 
     92                 if (!vis[to])
     93                 {
     94                     q.push(to);
     95                     vis[to] = 1;
     96                     cnt[to]++;
     97 
     98                     if (cnt[to] > n) return 1;
     99                 }
    100             }
    101         }
    102     }
    103 
    104     return 0;
    105 }
    106 
    107 int main()
    108 {
    109     int t;
    110     int cas = 0;
    111 
    112     scanf("%d",&t);
    113 
    114     while (t--)
    115     {
    116         printf("Case %d: ",++cas);
    117 
    118         int n,dis;
    119 
    120         scanf("%d%d",&n,&dis);
    121 
    122         init(n);
    123 
    124         for (int i = 1;i <= n;i++)
    125         {
    126             scanf("%d",&h[i].hei);
    127             h[i].id = i;
    128         }
    129 
    130         for (int i = 1;i < n;i++)
    131         {
    132             adde(i+1,i,-1);
    133         }
    134 
    135         sort(h+1,h+n+1);
    136 
    137         for (int i = 1;i < n;i++)
    138         {
    139             int x = min(h[i].id,h[i+1].id);
    140             int y = max(h[i].id,h[i+1].id);
    141             adde(x,y,dis);
    142         }
    143 
    144         int s = min(h[1].id,h[n].id);
    145         int en = max(h[1].id,h[n].id);
    146 
    147         bool f = spfa(s,n);
    148 
    149         if (f) printf("-1
    ");
    150         else printf("%d
    ",d[en]);
    151     }
    152 
    153     return 0;
    154 }
  • 相关阅读:
    MySql存储引擎MyISAM和InnoDB的区别
    Nginx下载安装
    科目三考试训练大纲
    解决The current branch is not configured for pull No value for key branch.master.merge found in config
    java实现截取6个汉字字母数字
    如何将git上的代码迁移到Coding上
    Python抓取博客园首页文章列表(带分页)
    Python实现抓取CSDN博客首页文章列表
    Python实现抓取CSDN热门文章列表
    linux目录的操作
  • 原文地址:https://www.cnblogs.com/kickit/p/7420977.html
Copyright © 2011-2022 走看看