• UVaLive 4128 Steam Roller (多决策最短路)


    题意:给定一个图,r 根横线, c 根竖线。告诉你起点和终点,然后从起点走,每条边有权值,如果是0,就表示无法通行。走的规则是:如果你在下个路要转弯,会使这段路的时间加倍,但是如果一条路同时是这样,那么也只算两倍。起点和终点他们相连的第一条边也算两倍。问你最短时间。

    析:把每个点拆成 8 个点(r, c, dir, doubled)分别下一步走哪个方向,是不是要加倍,然后每次枚举上一条,和新边,枚举上一边是不是加倍之后的,然后判断是不是要转弯,然后计算加不加倍,最后跑一次最短路,就好了。

    代码如下:

    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include <cstdio>
    #include <string>
    #include <cstdlib>
    #include <cmath>
    #include <iostream>
    #include <cstring>
    #include <set>
    #include <queue>
    #include <algorithm>
    #include <vector>
    #include <map>
    #include <cctype>
    #include <cmath>
    #include <stack>
    #include <sstream>
    #include <list>
    #include <assert.h>
    #include <bitset>
    #define debug() puts("++++");
    #define gcd(a, b) __gcd(a, b)
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define fi first
    #define se second
    #define pb push_back
    #define sqr(x) ((x)*(x))
    #define ms(a,b) memset(a, b, sizeof a)
    #define sz size()
    #define pu push_up
    #define pd push_down
    #define cl clear()
    #define all 1,n,1
    #define FOR(i,x,n)  for(int i = (x); i < (n); ++i)
    #define freopenr freopen("in.txt", "r", stdin)
    #define freopenw freopen("out.txt", "w", stdout)
    using namespace std;
    
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef pair<int, int> P;
    const int INF = 0x3f3f3f3f;
    const double inf = 1e20;
    const double PI = acos(-1.0);
    const double eps = 1e-8;
    const int maxn = 80000 + 10;
    const int maxm = 100 + 10;
    const ULL mod = 10007;
    const int dr[] = {-1, 0, 1, 0};
    const int dc[] = {0, -1, 0, 1};
    const char *de[] = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"};
    int n, m;
    const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    inline bool is_in(int r, int c) {
      return r >= 0 && r < n && c >= 0 && c < m;
    }
    const int UP = 0, LEFT = 1, DOWN = 2, RIGHT = 3;
    const int inv[] = {2, 3, 0, 1};
    int id[maxm][maxm][4][2], cnt;
    int g[maxm][maxm][4];
    
    int ID(int r, int c, int dir, int doubled){
      int &x = id[r][c][dir][doubled];
      return x == 0 ? x = ++cnt : x;
    }
    
    bool cango(int r, int c, int dir){
      if(!is_in(r, c))  return false;
      return g[r][c][dir] > 0;
    }
    
    struct Edge{
      int from, to, dist;
    };
    struct HeapNode{
      int d, u;
      bool operator < (const HeapNode &p) const{
        return d > p.d;
      }
    };
    
    struct Dijkstra{
      int n, m;
      vector<Edge> edges;
      vector<int> G[maxn];
      bool done[maxn];
      int d[maxn];
    
      void init(int n){
        this-> n = n;
        for(int i = 0; i < n; ++i)  G[i].cl;
        edges.cl;
      }
    
      void addEdge(int from, int to, int dist){
        edges.pb((Edge){from, to, dist});
        m = edges.sz;
        G[from].pb(m-1);
      }
    
      void dijkstra(int s){
        priority_queue<HeapNode> pq;
        ms(d, INF);  d[s] = 0;
        ms(done, 0);
        pq.push((HeapNode){0, s});
        while(!pq.empty()){
          HeapNode x = pq.top();  pq.pop();
          int u = x.u;
          if(done[u])  continue;
          done[u] = true;
          for(int i = 0; i < G[u].sz; ++i){
            Edge &e = edges[G[u][i]];
            if(d[e.to] > d[u] + e.dist){
              d[e.to] = d[u] + e.dist;
              pq.push((HeapNode){d[e.to], e.to});
            }
          }
        }
      }
    };
    Dijkstra dij;
    
    int readint(){ int x;  scanf("%d", &x);  return x; }
    
    int main(){
      int r1, c1, r2, c2, kase = 0;
      while(scanf("%d %d %d %d %d %d", &n, &m, &r1, &c1, &r2, &c2) == 6 && n){
        --r1, --r2, --c1, --c2;
        for(int r = 0; r < n; ++r){
          for(int c = 0; c < m-1; ++c)
            g[r][c][RIGHT] = g[r][c+1][LEFT] = readint();
          if(r != n-1)  for(int c = 0; c < m; ++c)
            g[r][c][DOWN] = g[r+1][c][UP] = readint();
        }
        dij.init(n * m * 8 + 1);
        cnt = 0;   ms(id, 0);
        for(int dir = 0; dir < 4; ++dir)  if(cango(r1, c1, dir))  // the edge of source
          dij.addEdge(0, ID(r1+dr[dir], c1+dc[dir], dir, 1), g[r1][c1][dir] * 2);
        FOR(r, 0, n)  FOR(c, 0, m) FOR(dir, 0, 4)  if(cango(r, c, inv[dir]))
          FOR(newdir, 0, 4)  if(cango(r, c, newdir))  FOR(doubled, 0, 2){
            int x = r + dr[newdir];
            int y = c + dc[newdir];
            int v = g[r][c][newdir], newdoubled = 0;
            if(dir != newdir){
              if(!doubled)  v += g[r][c][inv[dir]];  // the old edge double
              newdoubled = 1; v += g[r][c][newdir];  // the new edge double
            }
            dij.addEdge(ID(r, c, dir, doubled), ID(x, y, newdir, newdoubled), v);
          }
        dij.dijkstra(0);
        int ans = INF;
        FOR(dir, 0, 4)  if(cango(r2, c2, inv[dir]))
          for(int doubled = 0; doubled < 2; ++doubled){
            int v = dij.d[ID(r2, c2, dir, doubled)];
            if(!doubled)  v += g[r2][c2][inv[dir]];
            ans = min(ans, v);
          }
        printf("Case %d: ", ++kase);
        if(ans == INF)  puts("Impossible");
        else  printf("%d
    ", ans);
      }
      return 0;
    }
    

      

  • 相关阅读:
    Delphi 中流的使用
    关于 Delphi 中流的使用(9) 分割与合并文件的函数
    基于Windows字库的点阵数据提取方法
    Oracle 后台进程介绍
    面试-MySQL
    怎样预置桌面上的应用程序图标、快捷方式图标或者窗体小部件?
    配置 Phpstorm + Xdebug + xampp
    [jQuery] 选择器和事件
    数据挖掘算法学习(四)PCA算法
    基础数位DP小结
  • 原文地址:https://www.cnblogs.com/dwtfukgv/p/7610539.html
Copyright © 2020-2023  润新知