在这一周里看了一些博客,做了一些题目,但是做的题目有点少,看的都是关于搜索的博客,虽然在搜索方面没什么进展,但是在做题方面有了更多的体会和感悟,尤其是在周六晚上的codeforce上的题目,本来应该做出来的题,硬生生拖到最后还是没做出来,在写代码中出现了慌乱,导致自己都不知道做什么,这是不应该出现的情况。既然出现了这种情况,就应该克服这种情况。另外,看了这么多博客,还是得总结知识,以便以后回看。
以下列举几个典型例题:
1.电路维修(双端队列)
题意:题目是由左上角走到右下角,每个格子都有一个方向不同的对角线,这个题只能沿着对角线走,能改变对角线的方向改变一次操作数加一,求最小的操作数,这是我看到的第一个关于使用双端队列和广度优先搜索一起的。
题解:看的那位大佬的解法,他是用的边权,意思就是如果需要对角线改变方向,那个对角线的边权就为1,如果不需要对角线改变方向,对角线的边权就为0,用双端队列存放数据,边权为1的存放在队尾,而边权为0的存放在队首,那么最终队首元素就是那个操作数最少的元素。
以下是其中的代码:(其中还使用了pair)
#include <iostream>
#include <cstdio>
#include <deque>
using namespace std;
#define long long LL;
const int N = 600;
char str[N][N];
int n, m;
bool vis[N][N];
int dis[N][N];
int main()
{
int T;
cin >> T;
while (T--)
{
cin >> n >> m;
for (int i = 0; i < n; i++) cin >> str[i];
for (int i = 0; i <= n; i++)
for (int j = 0; j <= m; j++) vis[i][j] = 0, dis[i][j] = int(2e9);
if (n + m & 1) { cout << "NO SOLUTION\n"; continue; }
deque<pair<int, int> > deq;
deq.push_back({ 0, 0 });
dis[0][0] = 0;
while (!deq.empty())
{
auto t = deq.front(); deq.pop_front();
int x = t.first, y = t.second;
if (vis[x][y]) continue;
vis[x][y] = 1; // 出队后才是最短距离
for (int i = x - 1; i <= x; i++)
for (int j = y - 1; j <= y; j++)
{
int xx = x - 1 + 2 * (i - x + 1), yy = y - 1 + 2 * (j - y + 1);
if (i < 0 || i >= n || j < 0 || j >= m || vis[xx][yy]) continue;
int& d = dis[xx][yy];
if (i - x + 1 + j - y + 1 & 1) {
if (str[i][j] == '\\') {
d = min(d, dis[x][y] + 1);
deq.push_back({ xx, yy });
}
else {
d = min(d, dis[x][y]);
deq.push_front({ xx, yy });
}
}
else {
if (str[i][j] == '\\') {
d = min(d, dis[x][y]);
deq.push_front({ xx, yy });
}
else {
d = min(d, dis[x][y] + 1);
deq.push_back({ xx, yy });
}
}
}
}
cout << dis[n][m] << endl;
}
system("pause");
return 0;
}
2.HDU 1429:胜利大逃亡(续)
题意:这个是关于走地图的,有墙有门有钥匙,还有起点和终点,从起点开始走,拿到对应的钥匙,开对应的门,直到走到出口,求最少的操作数是否与过了已经限定好了的时间。
题解:利用三维数组来标记地点,前两维存坐标第三维存钥匙的状态,二进制来存钥匙,用位运算运算来取钥匙和开门,用广搜来做这个题目。
(1<<(m[nex.x][nex.y]-'A'))&nex.key//判断这个门是否能用钥匙开启
tmpkey|=(1<<(m[nex.x][nex.y]-'a'));//遇到钥匙,并存放该钥匙
3.POJ Flip Game
这个是关于位运算的,自己感觉比较典型,顺便写一下。
题意:棋盘中有十六个棋子,除了黑棋就是白棋,如果将一个棋子反转,周围的棋子也应该反转,要求用最少的步数完成对棋子的操作,全部变白或者是全部变黑。
题解:首先,用十六位的二进制来存放棋子,如果棋子为白色,则该位置上数位为1,如果是黑棋,则为0,反转时可以用异或运算来翻转棋子,那么最终状态为十六进制数为0或是65536(二进制:1111111111111111)
以上是对本次学习的总结,主要还是对广搜学的更多一点,对于这次周六的codeforce的做题情况来说非常不满意,主要还是自己学的不是很精,还需要加大做题量和各种知识点的涉及。