Gym - 101291C (很有意思的最短路)

题意:

给出一张地图和机器人还有出口的位置,地图上面有障碍。然后给出UDLR上下左右四种指令,遇到障碍物或者越界的指令会忽略,剩下的继续执行。

只要到达出口就算找到出口,然后给你一串指令,让你修改指令达到出口,删除或插入任意一个指令花费为1,问让机器人能够找到出口所花费最少。  

思路:

感觉很有意思的一道最短路,思路是把每个点分成变成指令长度个点+1,然后就相当于有n^3个点。然后指令是顺序执行的,所以当前点的状态最多到达

周围可到达点的同一状态。所以我们就可以建边,如果我们走到隔壁点的当前状态就相当于插入了一个指令,就当前点到隔壁点建条花费为1的边。还可以建立

当前点到当前点的下个状态的边,花费为1,相当于删除当前指令。

这道题WA了很久= =然后找到数据对拍,最后发现是因为少建了一种边,就是指令执行完了,然后走向下一个点指令执行完了的边没有建立。

代码:

/** @xigua */
#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <cstring>
#include <queue>
#include <set>
#include <string>
#include <map>
#include <climits>
#include <bitset>
#define PI acos(-1)
using namespace std;
typedef long long ll;
typedef double db;
const int maxn = 2e5 + 5;
const int mod = 1e9 + 7;
const int INF = 1e8 + 5;
const ll inf = 1e15 + 5;
const db eps = 1e-6;
char mapp[55][55], op[55];
int dx[] = {1, -1, 0, 0}, dy[] = {0, 0, 1, -1};
int n, m;
int cnt, head[maxn], dis[maxn];
struct Edge {
    int v, w, next;
    bool operator < (const Edge &rhs) const {
        return w > rhs.w;
    }
} e[maxn*5];

void add(int u, int v, int co) {
    e[cnt].v = v;
    e[cnt].w = co;
    e[cnt].next = head[u];
    head[u] = cnt++;
}

void init() {
    cnt = 0;
    memset(head, -1, sizeof(head));
}

void dij(int s, int len) {
    priority_queue<Edge> pq;
    for (int i = 1; i <= len; i++)
        dis[i] = INF;
    bool vis[maxn] = {0};
    dis[s] = 0;
    pq.push((Edge){s, 0});
    while (!pq.empty()) {
        Edge tmp = pq.top(); pq.pop();
        if (vis[tmp.v]) continue;
        vis[tmp.v] = 1;
        for (int i = head[tmp.v]; ~i; i = e[i].next) {
            Edge u = e[i];
            if (dis[u.v] > dis[tmp.v] + u.w) {
                dis[u.v] = dis[tmp.v] + u.w;
                pq.push((Edge){u.v, dis[u.v]});
            }
        }
    }
}

bool safe(int x, int y) {
    return x >= 1 && x <= n && y >= 1 && y <= m && mapp[x][y] != ‘#‘;
}

void solve() {
    while (cin >> n >> m) {
        init();
        for (int i = 1; i <= n; i++)
            scanf("%s", mapp[i] + 1);
        scanf("%s", op+1);
        int len = strlen(op + 1);
        int st, ed;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                if (mapp[i][j] == ‘R‘) st = (i - 1) * m + j;
                if (mapp[i][j] == ‘E‘) ed = (i - 1) * m + j;
                if (mapp[i][j] == ‘#‘) continue;
                for (int k = 1; k <= len; k++) {
                    for (int p = 0; p < 4; p++) {
                        int x = i + dx[p];
                        int y = j + dy[p];
                        if (safe(x, y)) {
                            int u = ((i - 1) * m + j) * (len + 1) + k;
                            int v = ((x - 1) * m + y) * (len + 1) + k;
                            add(u, v, 1);
                        }
                    }
                    int x = i, y = j;
                    if (op[k] == ‘R‘) y++;
                    else if (op[k] == ‘L‘) y--;
                    else if (op[k] == ‘U‘) x--;
                    else x++;
                    if (safe(x, y)) {
                        int u = ((i - 1) * m + j) * (len + 1) + k;
                        int v = ((x - 1) * m + y) * (len + 1) + k + 1;
                        add(u, v, 0);
                    }
                    else {
                        int u = ((i - 1) * m + j) * (len + 1) + k;
                        add(u, u + 1, 0);
                    }
                    int u = ((i - 1) * m + j) * (len + 1) + k;
                    add(u, u + 1, 1);
                }
                /* 就是这里  没有考虑到建立边 */
                for (int p = 0; p < 4; p++) {
                    int x = i + dx[p];
                    int y = j + dy[p];
                    if (safe(x, y)) {
                        int u = ((i - 1) * m + j) * (len + 1) + len + 1;
                        int v = ((x - 1) * m + y) * (len + 1) + len + 1;
                        add(u, v, 1);
                    }
                }
            }
        }
        dij(st * (len + 1) + 1, (n * m + 1) * (len + 1));
        int ans = INF;
        for (int i = 1; i <= len + 1; i++) {
            int cur = ed * (len + 1) + i;
            ans = min(ans, dis[cur]);
        }
        cout << ans << endl;
    }
}

int main() {
	int t = 1, cas = 1;
	//freopen("in.txt", "r", stdin);
	// freopen("out.txt", "w", stdout);
	//scanf("%d", &t);
	while (t--) {
		// printf("Case %d: ", cas++);
		solve();
	}
	return 0;
}
时间: 2024-10-08 12:04:37

Gym - 101291C (很有意思的最短路)的相关文章

一道很有意思的java线程题

这几天看结城浩的<java多线程设计模式>,跟着做一些习题,有几道题目很有意思,记录下自己的体会. 首先是题目(在原书212页,书尾有解答): public class Main { public static void main(String[] args) { try { Blackhole.enter(new Object()); } catch (InterruptedException e) { e.printStackTrace(); } } } public class Blac

右键弹出自定义菜单,很有意思呀!

<HTML><HEAD><TITLE>右键菜单</TITLE> <SCRIPT language="javascript"> <!-- function showmenuie5(){ var rightedge=document.body.clientWidth-event.clientX var bottomedge=document.body.clientHeight-event.clientY if (righte

ios各种手势,很有意思

一.概述 iPhone中处理触摸屏的操作,在3.2之前是主要使用的是由UIResponder而来的如下4种方式: - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event  - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event  - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent

分享一个很有意思的js,动态时钟显示,能跟随鼠标移动

原文:分享一个很有意思的js,动态时钟显示,能跟随鼠标移动 源代码下载地址:http://www.zuidaima.com/share/1550463688182784.htm

Java异常处理机制很有意思

前言:在网络上看到一篇<深入理解Java异常处理机制>,看完感觉自己也有一点小想法,的确在很多Java学者的眼里,异常处理机制不就是try catch finally吗,有啥好理解,很多时候,我也经常忽略这方面的内容,感觉没什么有意思的,那么我们来扎个小马步吧 1.经过对原作者的例子改造 package mwq; public class T1 { public static void main(String[] args) { boolean b = true; try { b = tb1(

看到一篇很有意思的文章,但是我们身边确实有这样的人

我在代码之路上曾经遇到过很多奇怪的对手,也遇到过奇怪的队友.我至少接触了五种不同的"代码斗士".其中一些有才的战友有助于开发工作的进行,而另一些看起来阻碍了我的每一个计划. 然而,他们全都在软件开发的"万神殿"中拥有一席之地.如果不能将这些不同风格的程序员协调好的话,你会发现你的项目会花费很多时间.不够稳定或者代码难以读懂等问题. 补漏灵型 该死,代码虽然不够完美,但是能工作就行了! 这种人是你公司的基础.当哪里出现差错的时候他会迅速的修补,在某种程度上,保证不会再

输出图形字符的命令(很有意思呦!)

今天学到了很有意思的三个命令:怎么有意思  快看下图啦! 这是Ubuntu系统下的三个命令,跟echo本质一样,但是输出的字符是图形的 ,很可爱! 以下是安装命令: sudo  apt-get update;sudo apt-get  install sysvbanner sudo  apt-get update;sudo apt-get  install toilet sudo  apt-get update;sudo apt-get  install figlet

记录一次很有意思的bug

情景是这样的: log 一直在狂打不止,直到打满了磁盘, 在上传文件的时候发现只要是超过了1m就传不上去. 解决策略 首先肯定是清除磁盘 干掉无用的log,清除了之后发现问题并没有解决,于是使用top命令查看内存使用情况 发现内存使用并不高,于是这个问题就很有意思了. 有如下几种猜测: 1.程序内存泄漏 导致内存无法有效回收 经过重启,仔细查看每个进程的内存情况发现 并非这种情况. 2.依稀记得linux文件目录有大小限制  翻阅大量文档发现大小制约的其实是Inode ,只有在大量的小文件的写入

一些很有意思的站点

这篇博客主要会收录一些比较有意思/实用的url https://csacademy.com/app/graph_editor 图论作图很有用的一个工具 原文地址:https://www.cnblogs.com/lizbaka/p/10257621.html