2015 Astar Contest - Round 2B 题解

1001 追星族

题目大意

平面内有N个点,Ti时刻在(Xi, Yi)点有演出
在0时刻度度熊从任意起点出发,移动速度为1
设计路线使得在所有的演出时刻,它距离演出地点距离的最大值最小
答案输出分数形式

算法思路

平面上的曼哈顿距离,可以通过坐标转换,变成1维数轴上的问题
即两点之间的曼哈顿距离等于两点在x + y数轴空间和x - y数轴空间上距离的最大值
对于本题,可以二分一个答案,然后判断在两个数轴上是否同时可行
按照时间排序后,维护区间的交集
每次将原区间向左右扩展可以移动的距离,再与当前坐标两侧的可行区域求交
判定条件为最后的区域是否为空
由于可行区域的端点可能位于两个整点之间,所以事先将所有坐标乘2,最后根据奇偶输出

时间复杂度: O(NlogN)

代码

/**
 * Copyright © 2015 Authors. All rights reserved.
 * 
 * FileName: A.cpp
 * Author: Beiyu Li <sysulby@gmail.com>
 * Date: 2015-06-09
 */
#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;

#define rep(i,n) for (int i = 0; i < (n); ++i)
#define For(i,s,t) for (int i = (s); i <= (t); ++i)
#define foreach(i,c) for (__typeof(c.begin()) i = c.begin(); i != c.end(); ++i)

typedef long long LL;
typedef pair<int, int> Pii;

const int inf = 0x3f3f3f3f;
const LL infLL = 0x3f3f3f3f3f3f3f3fLL;

const int maxn = 50000 + 5;

int n;
struct Point {
        int t;
        LL x[2];
        bool operator<(const Point &p) const { return t < p.t; }
} a[maxn];

bool check(LL d)
{
        rep(o,2) {
                LL l = a[0].x[o] - d, r = a[0].x[o] + d;
                for (int i = 1; i < n; ++i) {
                        LL dt = a[i].t - a[i-1].t;
                        l = max(l - dt * 2, a[i].x[o] - d);
                        r = min(r + dt * 2, a[i].x[o] + d);
                        if (l > r) return false;
                }
        }
        return true;
}

int main()
{
        int T, cas = 0;
        scanf("%d", &T);

        while (T--) {
                scanf("%d", &n);
                rep(i,n) {
                        int x, y;
                        scanf("%d%d%d", &x, &y, &a[i].t);
                        a[i].x[0] = (LL)(x + y) * 2;
                        a[i].x[1] = (LL)(x - y) * 2;
                }
                sort(a, a + n);
                LL l = 0, r = infLL;
                while (l < r) {
                        LL mid = l + ((r - l) >> 1);
                        if (check(mid)) r = mid;
                        else l = mid + 1;
                }
                printf("Case #%d:\n", ++cas);
                printf("%I64d/%I64d\n", r & 1? r: r / 2, (r & 1) + 1);
        }

        return 0;
}

1002 连接的管道

题目大意

有一个片N*M大小的农田,每块田有个高度,两块相邻的田之间修管道的代价为高度差
现在要用管道把所有农田连接起来,问最小代价

算法思路

网格图版的最小生成树

时间复杂度: O(N2logN2)

代码

/**
 * Copyright © 2015 Authors. All rights reserved.
 * 
 * FileName: B.cpp
 * Author: Beiyu Li <sysulby@gmail.com>
 * Date: 2015-06-09
 */
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <queue>

using namespace std;

#define rep(i,n) for (int i = 0; i < (n); ++i)
#define For(i,s,t) for (int i = (s); i <= (t); ++i)
#define foreach(i,c) for (__typeof(c.begin()) i = c.begin(); i != c.end(); ++i)

typedef long long LL;
typedef pair<int, int> Pii;

const int inf = 0x3f3f3f3f;
const LL infLL = 0x3f3f3f3f3f3f3f3fLL;

const int maxn = 1000 + 5;

int n, m;
int a[maxn][maxn];
int dis[maxn][maxn];
bool vis[maxn][maxn];
int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};

bool inside(int x, int y) { return 0 <= x && x < n && 0 <= y && y < m; }

int prim()
{
        int res = 0;
        priority_queue<Pii> que;
        memset(dis, 0x3f, sizeof(dis));
        memset(vis, false, sizeof(vis));
        dis[0][0] = 0; que.push(Pii(0, 0));
        while (!que.empty()) {
                int x = que.top().second / m, y = que.top().second % m;
                que.pop();
                if (vis[x][y]) continue; vis[x][y] = true, res += dis[x][y];
                rep(i,4) {
                        int nx = x + dx[i], ny = y + dy[i];
                        if (!inside(nx, ny)) continue;
                        int w = abs(a[x][y] - a[nx][ny]);
                        if (w < dis[nx][ny]) {
                                dis[nx][ny] = w;
                                que.push(Pii(-dis[nx][ny], nx * m + ny));
                        }
                }
        }
        return res;
}

int main()
{
        int T, cas = 0;
        scanf("%d", &T);

        while (T--) {
                scanf("%d%d", &n, &m);
                rep(i,n) rep(j,m) scanf("%d", &a[i][j]);
                printf("Case #%d:\n", ++cas);
                printf("%d\n", prim());
        }

        return 0;
}

1003 棋盘占领

题目大意

有一个N*M的棋盘,一开始占领了一些格子
如果一个格子上下左右相邻的4个格子中,存在两个有公共点的格子被占领,则该格子也被占领
问最后有多少个格子被占领

算法思路

一旦一个格子被占领,最多改变其上下左右相邻的4个格子的状态
使用BFS,每次考察与队头相邻的格子是否即将被占领,入队即可

时间复杂度: O(N2)

代码

/**
 * Copyright © 2015 Authors. All rights reserved.
 * 
 * FileName: C.cpp
 * Author: Beiyu Li <sysulby@gmail.com>
 * Date: 2015-06-09
 */
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>

using namespace std;

#define rep(i,n) for (int i = 0; i < (n); ++i)
#define For(i,s,t) for (int i = (s); i <= (t); ++i)
#define foreach(i,c) for (__typeof(c.begin()) i = c.begin(); i != c.end(); ++i)

typedef long long LL;
typedef pair<int, int> Pii;

const int inf = 0x3f3f3f3f;
const LL infLL = 0x3f3f3f3f3f3f3f3fLL;

const int maxn = 500 + 5;

int n, m, g;
bool vis[maxn][maxn];
int dx[] = {-1, 0, 1, 0}, dy[] = {0, -1, 0, 1};

bool inside(int x, int y) { return 0 <= x && x < n && 0 <= y && y < m; }

bool check(int x, int y)
{
        rep(i,4) {
                int x1 = x + dx[i], y1 = y + dy[i];
                int x2 = x + dx[(i+1)%4], y2 = y + dy[(i+1)%4];
                if (inside(x1, y1) && vis[x1][y1] &&
                                inside(x2, y2) && vis[x2][y2]) return true;
        }
        return false;
}

int main()
{
        int T, cas = 0;
        scanf("%d", &T);

        while (T--) {
                scanf("%d%d%d", &n, &m, &g);
                int res = 0, x, y;
                queue<Pii> que;
                memset(vis, false, sizeof(vis));
                while (g--) {
                        scanf("%d%d", &x, &y);
                        que.push(Pii(--x, --y));
                }
                while (!que.empty()) {
                        int x = que.front().first, y = que.front().second;
                        que.pop();
                        if (vis[x][y]) continue; vis[x][y] = true, ++res;
                        rep(i,4) {
                                int nx = x + dx[i], ny = y + dy[i];
                                if (!inside(nx, ny)) continue;
                                if (check(nx, ny)) que.push(Pii(nx, ny));
                        }
                }
                printf("Case #%d:\n", ++cas);
                printf("%d\n", res);
        }

        return 0;
}

1004 魔法因子

题目大意

对于给出的实数X,找出所有的不超过10位的正整数N
满足N*X依然是整数,且刚好是N首位和末位交换位置的形式

算法思路

N=a10k+b10+c ,有 NX=c10k+b10+a
可得 b=X(a10k+c)(c10k+a)1X÷10
X 写成分数形式X=yz得, b=y(a10k+c)z(c10k+a)zy÷10
由此,我们可以枚举a、c和k的值,确定能否得到满足范围的b

时间复杂度: O(103)

代码

/**
 * Copyright © 2015 Authors. All rights reserved.
 * 
 * FileName: D.cpp
 * Author: Beiyu Li <sysulby@gmail.com>
 * Date: 2015-06-10
 */
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>

using namespace std;

#define rep(i,n) for (int i = 0; i < (n); ++i)
#define For(i,s,t) for (int i = (s); i <= (t); ++i)
#define foreach(i,c) for (__typeof(c.begin()) i = c.begin(); i != c.end(); ++i)

typedef long long LL;
typedef pair<int, int> Pii;

const int inf = 0x3f3f3f3f;
const LL infLL = 0x3f3f3f3f3f3f3f3fLL;

int main()
{
        int T, cas = 0;
        scanf("%d", &T);

        while (T--) {
                double x;
                scanf("%lf", &x);
                int y = x * 1000000 + 0.5, z = 1000000, m = (z - y) * 10;
                vector<LL> vec;
                for (LL i = 1, p = 10; i < 10; ++i, p *= 10) {
                        for (int a = 1; a < 10; ++a) rep(c,10) {
                                LL b = y * (a * p + c) - z * (c * p + a);
                                if (b % m) continue; b /= m;
                                if (0 <= b && b * 10 < p)
                                        vec.push_back(a * p + b * 10 + c);
                        }
                }
                sort(vec.begin(), vec.end());
                printf("Case #%d:\n", ++cas);
                printf("%d\n", (int)vec.size());
                foreach(it,vec) printf("%I64d%c", *it, " \n"[it==--vec.end()]);
        }

        return 0;
}

1005 序列变换

题目大意

给出一个整数数列,要求调整最少的数,使得该数列严格递增

算法思路

对于任意两个无需调整的数,必须有 AjAjji ,即 AiiAjj
因此,将数列每一位的值减去下标,则无需调整的数必定构成非降子序列
找出最长的非降子序列长度,用总长度减去就是最少需要调整的个数

时间复杂度: O(NlogN)

代码

/**
 * Copyright © 2015 Authors. All rights reserved.
 * 
 * FileName: E.cpp
 * Author: Beiyu Li <sysulby@gmail.com>
 * Date: 2015-06-10
 */
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cstdlib>

using namespace std;

#define rep(i,n) for (int i = 0; i < (n); ++i)
#define For(i,s,t) for (int i = (s); i <= (t); ++i)
#define foreach(i,c) for (__typeof(c.begin()) i = c.begin(); i != c.end(); ++i)

typedef long long LL;
typedef pair<int, int> Pii;

const int inf = 0x3f3f3f3f;
const LL infLL = 0x3f3f3f3f3f3f3f3fLL;

const int maxn = 100000 + 5;

int n;
int a[maxn], g[maxn];

int main()
{
        int T, cas = 0;
        scanf("%d", &T);

        while (T--) {
                scanf("%d", &n);
                rep(i,n) scanf("%d", &a[i]);
                memset(g, 0x3f, sizeof(g));
                int ret = 0;
                rep(i,n) {
                        int p = upper_bound(g + 1, g + n + 1, a[i] - i) - g;
                        ret = max(ret, p);
                        g[p] = a[i] - i;
                }
                printf("Case #%d:\n", ++cas);
                printf("%d\n", n - ret);
        }

        return 0;
}

1006 翻转游戏

题目大意

在一个N*M的格子上,有一些格子是黑色,有一些是白色
每选择一个格子按一次,格子以及周围边相邻的格子都会翻转颜色
有一些格子坏掉了,无法被按下,问能否把所有格子都变成白色

算法思路

首先,每个格子最多操作一次,因此每个格子操作与否可以用0/1状态表示
其次,由于操作的效果是置反,所以每个格子的状态改变,相当于相关操作的异或
最后,由于每次操作最多影响到上面一行,所以当第一行的操作确定后
第一行的状态只能通过第二行的操作来调整,因此第二行的操作也随之确定
由此,每个格子的操作都可以表示为第一行操作的线性异或组合
这样,我们把第一行的操作设为M个0/1变量,每个格子的操作都是一个异或方程
对于K个坏掉的格子,以及第N+1行的格子(假设存在),操作的结果必须是0
答案等价于这些方程组是否有解,可以用高斯消元求解

时间复杂度: O(N3)

代码

/**
 * Copyright © 2015 Authors. All rights reserved.
 * 
 * FileName: F.cpp
 * Author: Beiyu Li <sysulby@gmail.com>
 * Date: 2015-06-10
 */
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <bitset>

using namespace std;

#define rep(i,n) for (int i = 0; i < (n); ++i)
#define For(i,s,t) for (int i = (s); i <= (t); ++i)
#define foreach(i,c) for (__typeof(c.begin()) i = c.begin(); i != c.end(); ++i)

typedef long long LL;
typedef pair<int, int> Pii;

const int inf = 0x3f3f3f3f;
const LL infLL = 0x3f3f3f3f3f3f3f3fLL;

const int maxn = 256 + 5;

int gauss(bitset<maxn> a[], int n, int m)
{
        int rank = 0;
        for (int i = 0; i < m; ++i) {
                int r = rank;
                while (r < n && !a[r].test(i)) ++r;
                if (r >= n) continue;
                swap(a[rank], a[r]);
                for (int j = rank + 1; j < n; ++j)
                        if (a[j].test(i)) a[j] ^= a[rank];
                ++rank;
        }
        for (int i = rank; i < n; ++i) if (a[i].test(m)) return -1;
        return rank;
}

int n, m, k;
bool g[maxn][maxn], a[maxn][maxn];
bitset<maxn> b[maxn][maxn], vec[maxn*2];

int main()
{
        int T, cas = 0;
        scanf("%d", &T);

        while (T--) {
                scanf("%d%d%d", &n, &m, &k);
                rep(i,n) {
                        char s[maxn];
                        scanf("%s", s);
                        rep(j,m) g[i][j] = (s[j] == 'B');
                }
                memset(a, true, sizeof(a));
                rep(i,k) {
                        int x, y;
                        scanf("%d%d", &x, &y);
                        a[--x][--y] = false;
                }
                k = 0;
                rep(j,m) b[0][j].reset(), b[0][j].set(j);
                rep(i,n) {
                        rep(j,m) if (!a[i][j]) vec[k++] = b[i][j];
                        rep(j,m) {
                                b[i+1][j] = b[i][j];
                                if (i) b[i+1][j] ^= b[i-1][j];
                                if (j) b[i+1][j] ^= b[i][j-1];
                                if (j + 1 < m) b[i+1][j] ^= b[i][j+1];
                                if (g[i][j]) b[i+1][j].flip(m);
                        }
                }
                rep(j,m) vec[k++] = b[n][j];
                printf("Case #%d:\n", ++cas);
                puts(~gauss(vec, k, m)? "YES": "NO");
        }

        return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Hybrid-Astar是一种路径规划算法,它结合了A*算法(Astar)和RS距离(Reeds-Shepp距离)来寻找车辆的最优路径。使用Matlab实现这个算法需要2016a版本或更高版本。 首先,Hybrid-Astar算法以车辆的运动学模型为节点,在搜索过程中使用A*算法来计算当前点到终点的最短路径。A*算法通过综合考虑实际代价(g(n))和启发式代价(h(n))来选择下一个节点。在这里,h(n)函数的估计代价是通过计算当前点到终点的Astar距离和RS距离两者中的最大值得到的。 其次,RS距离是一种考虑了车辆转弯半径的距离度量方式。它使用车辆的运动学模型来计算车辆在转弯过程中可能遇到的最小转弯半径,并将其作为路径规划的一个重要因素。 在Matlab中实现Hybrid-Astar算法,可以使用基本的路径规划算法框架,并结合A*算法和RS距离的计算来实现。具体实现步骤可以按照以下方式进行: 1. 定义车辆的运动学模型,包括车辆的位置、速度、加速度等参数。 2. 定义启发式函数h(n),根据当前点到终点的Astar距离和RS距离两者中的最大值来估计代价。 3. 使用A*算法进行路径搜索,考虑实际代价g(n)和启发式代价h(n),选择下一个节点。 4. 在搜索过程中,根据车辆的运动学模型和RS距离计算车辆在转弯过程中的最小转弯半径。 5. 循环执行路径搜索,直到找到终点或搜索完所有可能的节点。 6. 返回最优路径。 这是Hybrid-Astar算法在Matlab中的一种实现方式,你可以根据具体需求进行调整和优化。以上是关于Hybrid-Astar matlab实现的简要介绍。<span class="em">1</span><span class="em">2</span> #### 引用[.reference_title] - *1* [Hybrid-Astar(混合A星算法)路径规划MATLAB代码](https://download.csdn.net/download/weixin_56691527/87614899)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [混合A星算法-Hybrid_Astar(matlab)](https://download.csdn.net/download/qq_49747343/13219383)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值