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;
}

  

时间: 2024-10-12 20:07:41

UVaLive 4128 Steam Roller (多决策最短路)的相关文章

UVALive 4128 Steam Roller 蒸汽式压路机(最短路,变形) WA中。。。。。

题意:给一个由n*m个正方形格子组成的矩形,其中每个格子的边都是可以走的,长度给定,规定:如果在进入该路前需要拐弯,或者走完该路需要拐弯,都是需要付出双倍距离的(每条路最多算2倍).问从起点到终点的最短路经长. 思路:这个题目超级难搞,思路很简单,就是很麻烦!!!我将1个点4个方向的路长都记录下来,然后进行最短路,只要一个点的某个方向更新了,就进队.所有都考虑得差不多了,就是WA... 步骤 : (1)起点不进队,因为起点出发都需要双倍,况且,如果起点路长为0的话,其他点就不能路过起点了,所以将

UVA 1078 - Steam Roller(最短路)

UVA 1078 - Steam Roller 题目链接 题意:给定一个地图,要求起点走到终点需要的时间,如果进入一个转弯位置,则进入和出去的时候时间要加倍 思路:最短路,关键在于如何建模,每个结点d[x][y][d][flag]表示在x, y结点,方向为d,是否加倍过了,这样就可以把每个结点之间对应的关系建边,做最短路即可 代码: #include <cstdio> #include <cstring> #include <vector> #include <q

UVALive - 4128

https://vjudge.net/problem/UVALive-4128 原文地址:https://www.cnblogs.com/ling-zhi/p/11619162.html

训练指南 UVALive - 4080(最短路Dijkstra + 边修改 + 最短路树)

layout: post title: 训练指南 UVALive - 4080(最短路Dijkstra + 边修改 + 最短路树) author: "luowentaoaa" catalog: true mathjax: true tags: - Dijkstra - 最短路树 - 图论 - 训练指南 Warfare And Logistics UVALive - 4080 题意 ①先求任意两点间的最短路径累加和,其中不连通的边权为L ②删除任意一条边,求全局最短路径和的最大值 题解

UVALive 7302 (最短路)

Probelm Terrorists 题目大意 给一张n个点,m条边的无向图.共有q个询问,每次询问u到v的最短路. n <= 100000 ,  n-1 <= m <= n + 50 , q <= 50000. 解题分析 注意到m的范围比较特殊,所以可以看成是一棵树加上若干条非树边. 将所有的非树边所连接的点取出来,每个关键点跑一次单源最短路. 对于一次询问u,v,其可能的答案路径为直接从树上跑,或者经过一个关键点中转. 参考程序 1 #include <cstdio>

UVALive 6885 Flowery Trails 最短路枚举

题目连接: http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=129723 题意: 给你一个n点m图的边 1到n有多条最短路,问你所有经过的边的总和*2是多少 题解: 对1,n分别求单源最短路径上spfa 枚举某条边是否为最短上的边 即 边权+disA[i] + disB[i] = 最短路长度,就是答案 #include<bits/stdc++.h> using namespace std; const int N =

UVALive 4870 Roller Coaster --01背包

题意:过山车有n个区域,一个人有两个值F,D,在每个区域有两种选择: 1.睁眼: F += f[i], D += d[i] 2.闭眼: F = F ,     D -= K 问在D小于等于一定限度的时候最大的F. 解法: 用DP来做,如果定义dp[i][j]为前 i 个,D值为j的情况下最大的F的话,由于D值可能会增加到很大,所以是存不下的,又因为F每次最多增加20,那么1000次最多增加20000,所以开dp[1000][20000],dp[i][j]表示前 i 个,F值为j的情况下最小的D.

UVAlive 7414 Squeeze the Cylinders a,b,c三种步数 搜索+最短路

You are playing a game with your elder brother.First, a number of circles and arrows connecting some pairs of the circles are drawn on the ground.Two of the circles are marked as the start circle and the goal circle.At the start of the game, you are

UVALive - 3661 Animal Run (平面图+最小割+对偶图+最短路)

题目大意:有很多只小动物要从左上角跑到右下角,给出每条线路所需的人手,问至少需要多少人手,才能将所有动物抓住 解题思路:最小割,就是最小割,但是用最大流处理不了,边太多了 具体可以参考算法合集之<浅析最大最小定理在信息学竞赛中的应用> 知道了这个后,这题估计就可以解了 给出我的建图方式 将每一个小三角形从左往右,从上到下依次编号为1-2-3.. 每行的同一个三角行的编号差就是2 * (m - 1) 如图 #include <cstdio> #include <cstring&