#4461. 宝藏

题意

在一座小岛上,有一片神奇的森林,每一年这里都会出现宝藏。

宝藏出现的出现位置只可能是 N N N 个位置中的一个。

在接下来的 Q Q Q 年里,E.Space 要去寻找宝藏。

由于 E.Space 不会飞,所以他要乘直升机前往。

森林会发生变化,E.Space 会选择最方便着陆的位置着陆,第 i i iE.Space 要在第 s i s_i si 个位置着陆。

森林很茂密,E.Space 只能步行前进。他找到了 M M M 条可以尝试通过的小路,第 i i i 条小路连接第 a i a_i ai 和第 b i b_i bi 个位置,E.Space 期望要花 c i c_i ci 的时间通过。此外,凭借 E.Space自身的力量,他不能够开拓任何道路。

除了有坎坷的路,森林中还有结界。

每个结界可以控制一个位置,使 E.Space 不能进出这个位置。

要破解结界,E.Space 需要找到对应的晶石。用晶石敲击结界,结界就会瓦解。

每个结界对应的晶石是唯一的。

E.Space 可以同时带着多块晶石。

森林中一共有 k k k 个结界。其中第 i i i 个结界控制着第 v i v_i vi 个位置,对应的晶石放在第 z i z_i zi 个位置。

每一年,结界都会被重置。也就是说,所有结界都会恢复,并且所有晶石都会回到原来的位置。

虽然森林会发生变化,但是所有的道路,结界,晶石的位置以及各种属性都不会变化,那 N N N 个位置也不会改变,森林的变化只会影响到在每个位置上着陆的方便程度。

由于 E.Space 是有备而来,所以他肯定会带藏宝图,也就是说,他知道宝藏的具体位置。第 i i i 年宝藏的位置是 t i t_i ti

E.Space 想知道,他每一年能否找到宝藏,以及他每一年从直升机着陆到找到宝藏,期望的步行时间至少是多少。

特殊地,如果 E.Space 的降落位置被结界控制,那么他就没法降落,于是他也一定找不到宝藏。

数据范围

保证 $N \le 400, M \le 10^5, k \le 16, Q \le 2 \times 10^5 , v_i , z_i, 1 \le v_i,z_i \le N, 1 \le s_i, t_i \le N , c_i \le 10^5 $ 。
子任务 1(6 pts): k = 0 k = 0 k=0
子任务 2(11 pts): N ≤ 20 , k ≤ 4 N \le 20, k \le 4 N20,k4
子任务 3(17 pts): N ≤ 50 , k ≤ 7 N \le 50, k \le 7 N50,k7
子任务 4(18 pts): N ≤ 250 , k ≤ 10 , s i = 1 N \le 250, k \le 10, s_i = 1 N250,k10,si=1
子任务 5(21 pts): N ≤ 250 , k ≤ 10 N \le 250, k \le 10 N250,k10
子任务 6(11 pts): k ≤ 14 k \le 14 k14
子任务 7(9 pts): k ≤ 15 k \le 15 k15
子任务 8(7 pts):无特殊限制。

题解

暴力状压最短路的瓶颈在于 n 3 n^{3} n3 2 k 2^{k} 2k要乘在一起,而两者皆不太可优化,考虑是否能将它们分开,即求n个点之间的最短路时不计状态(即不经过关键点(有宝石或有结界)),计状态时点数不要到n。发现对于s到t,中途经过了一些关键点,而关键点数量不多,这样就容易想到将路径分为先到一个关键点,经过一系列关键点,最后到达终点。所以可以枚举第一个和最后一个关键点,关键点之间用状压最短路,任意两点之间不经过关键点直接求最短路即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这个任务我可以帮你完成。我们可以按照以下步骤进行设计: 1. 首先需要通过输入行数和列数来生成地图,我们可以使用二维字符数组来表示地图,其字符“#”表示墙,字符“.”表示空地,字符“O”表示角色起始位置,字符“X”表示宝藏所在位置。 2. 在生成地图后,需要随机生成宝藏位置和角色起始位置。我们可以使用rand()函数生成两个不同的随机数作为宝藏和角色的坐标。 3. 接下来就是游戏的逻辑部分,需要循环读取玩家的输入,并根据输入来移动角色。如果角色移动到宝藏所在位置,则游戏结束,输出恭喜信息。 4. 在移动角色时,需要先判断移动后的位置是否越界,如果越界则不移动。如果不越界,则需要判断移动后的位置是否为墙,如果为墙则不移动。如果不是墙,则可以移动角色到该位置。 5. 在移动角色后,需要更新地图的显示,将原来的角色位置和宝藏位置改为“.”,将移动后的角色位置改为“O”,如果移动的位置是宝藏位置,则将该位置改为“$”。 下面是一个简单的代码实现,仅供参考: ```c++ #include <iostream> #include <cstdlib> #include <ctime> using namespace std; const int MAX_ROW = 10; const int MAX_COL = 10; void printMap(char map[MAX_ROW][MAX_COL], int row, int col) { for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { cout << map[i][j]; } cout << endl; } } int main() { srand(time(NULL)); int row, col; char map[MAX_ROW][MAX_COL]; cout << "请输入地图的行数和列数:"; cin >> row >> col; // 生成地图 for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { if (i == 0 || i == row - 1 || j == 0 || j == col - 1) { map[i][j] = '#'; } else { map[i][j] = '.'; } } } // 随机生成宝藏位置和角色起始位置 int treasureRow, treasureCol, playerRow, playerCol; do { treasureRow = rand() % (row - 2) + 1; treasureCol = rand() % (col - 2) + 1; playerRow = rand() % (row - 2) + 1; playerCol = rand() % (col - 2) + 1; } while (treasureRow == playerRow && treasureCol == playerCol); map[treasureRow][treasureCol] = 'X'; map[playerRow][playerCol] = 'O'; // 开始游戏 char direction; while (true) { printMap(map, row, col); cout << "请输入移动方向(w/a/s/d):"; cin >> direction; int newRow = playerRow, newCol = playerCol; switch (direction) { case 'w': newRow--; break; case 'a': newCol--; break; case 's': newRow++; break; case 'd': newCol++; break; default: continue; } if (newRow < 1 || newRow >= row - 1 || newCol < 1 || newCol >= col - 1) { continue; } else if (map[newRow][newCol] == '#') { continue; } else { map[playerRow][playerCol] = '.'; if (newRow == treasureRow && newCol == treasureCol) { map[newRow][newCol] = '$'; printMap(map, row, col); cout << "游戏结束,恭喜你完成游戏。" << endl; break; } else { map[newRow][newCol] = 'O'; playerRow = newRow; playerCol = newCol; } } } return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值