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

Posted dwtfukgv

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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\n", ans);
  }
  return 0;
}

  

以上是关于UVaLive 4128 Steam Roller (多决策最短路)的主要内容,如果未能解决你的问题,请参考以下文章

UVA1078 Steam Roller

bzoj4128 Matrix

BZOJ 4128

LA 4128

BZOJ_4128_Matrix_矩阵乘法+哈希+BSGS

题解Matrix BZOJ 4128 矩阵求逆 离散对数 大步小步算法