#include <iostream>
#include <cstdio>
#include <unordered_map>
#include <string>
#include <sstream>
using namespace std;

int main() {
  string line;
  while (getline(cin, line)) {
    istringstream linestream(line);
    int sum=0;
    int x;
    while (linestream >> x) {
      sum += x;
    }
    cout<<sum<<endl;
  }
}

除了将bitmap转化为int之类的,还可以直接用string.

同时可以用unordered_map<string,bool>记录状态是否访问过。

同时注意string的一个char的范围不只是0、1,因此还可以用来计数之类的

  1. 记录 已经搜索过的节点 的结果值。当下次访问到这个节点时,直接返回。
  2. 将当前已经进行过的步骤,与 已经计算出来的、可能不是最优解的 结果 进行对比,以便剪枝。
  3. 将节点排好序,以便2.能够发挥更好的剪枝效果

dfs可以分两种,一种自上而下的将结果传递给下层,如采用already_count之类的.

第二种则是像这样:dfs()返回整个问题的答案,而一个问题可以分解为多个子问题。如果可以这样,那么这样更好,因为感觉像这样dfs更容易缕清思路。

dfs时注意记忆化。

dfs时,一种更好的实践是在父节点要向下递归时,不判断子节点是否为空。而是在访问当前节点时,判断是否为空。这种将事情推给子节点自己去判断 比较思路清晰。

dfs时超时,可考虑将原先的数据排序,看能否加快

最近继续做bfs tag的题,有了一些新的思索。

  1. 每次bfs的时候,我们总把新元素放到队列后面。但其实我们常常遇到的这种情况 是另外一种情况的简化版,在那一种hard模式的版本中,队列是用的双端队列。
    1. 若新元素与当前相比 并没有实际的进展,则新元素被放到队首,反之放到队尾。这时,整个双端队列分为两级、分为两部分,前面的是同一级的,后面的下一级的。具体题型见lc1263 推箱子

2. 在bfs时,我们使用vis来标记某个元素是否曾经访问过。在一个图中,若这种遍历边 并 判断是否曾经访问过的行为就有很多时间开销了,那我们就可以采用list来记录某个节点的边们,并将访问过的边去掉,具体题目见lc1345 跳跃游戏IV。list相关代码如下:

        auto it = list.begin();
        while (it != list.end()) {
          int next_x = (*it);
          if (!vis[next_x]) {
            vis[next_x] = true;
            q.push(next_x);
            if (next_x == desi) {
              return step;
            }
            list.erase(it++);
          } else {
            it++;
          }
        }

记录录路径:开一个pre数组,在每次松弛bai边的时候(就是在执行duif d[j]+cost[k]<d[i] then d[i]:=d[j]+cost[k]的时候),这时如果d[i]被更新了,就将pre[i]:=j,表示当前到zhii点的最短路dao径中,j是i的前驱结点。在做完spfa时,
对于结点i,不断地i:=pre[i]直到i=源点,这途中的点即为路径。

判断负权环:因为用了队列版维护d数组,如果i结点入队次数大于等于n次,则有负权权环

vis的目的其实并不是已经访问过哪些节点,而是记录【[在当前步骤] 或 [之前的步骤]】中已经访问过的状态。因为之前已经访问过了这些状态,而之前那些访问用的步骤更少,因此之后就没必要再次访问这些状态了。

当用bfs用于记录到达某个状态的步骤时,则若某个节点 【曾经访问过】或【通步骤的其他状态已经将这个节点加入队列】,则不用再将这个节点加入队列:

 while (!sourceq.empty()) {
      level_count = sourceq.size();
      while ((level_count--) > 0) {
        auto p = sourceq.front();
        sourceq.pop(); 
        for (int i=0; i<4; i++) {
          int subx = p.first + dx[i];
          int suby = p.second + dy[i];
          if (subx >= 0 && suby >= 0 && subx < m && suby < n) {
            if (A[subx][suby] == 1) {
              return step;
            } else if (A[subx][suby] == 0 && vis2[subx][suby] == 0){
              sourceq.push({subx,suby});
              vis2[subx][suby]=1;
            }
          }
        }
      }

或者:

while (!sourceq.empty()) {
      level_count = sourceq.size();
      while ((level_count--) > 0) {
        auto p = sourceq.front();
        sourceq.pop();
        if (vis2[p.first][p.second] == 1) {
          continue;
        }
        vis2[p.first][p.second] = 1;
        for (int i=0; i<4; i++) {
          int subx = p.first + dx[i];
          int suby = p.second + dy[i];
          if (subx >= 0 && suby >= 0 && subx < m && suby < n) {
            if (A[subx][suby] == 1) {
              return step;
            } else if (A[subx][suby] == 0){
              sourceq.push({subx,suby});
            }
          }
        }
      }
      step++;
    }

但不能这样:

 while (!sourceq.empty()) {
      level_count = sourceq.size();
      while ((level_count--) > 0) {
        auto p = sourceq.front();
        sourceq.pop();
        // 1:
        if (vis2[p.first][p.second] == 1) {
          continue;
        }
        vis2[p.first][p.second] = 1;
        for (int i=0; i<4; i++) {
          int subx = p.first + dx[i];
          int suby = p.second + dy[i];
          if (subx >= 0 && suby >= 0 && subx < m && suby < n) {
            if (A[subx][suby] == 1) {
              return step;
            } else if (A[subx][suby] == 0 && vis2[subx][suby] == 0){
              // 2:
              sourceq.push({subx,suby});
              vis2[subx][suby]=1;
            }
          }
        }
      }

这样做的话,因为2处已经将vis2[subx][suby]设置为1,则访问这个节点时,因为1处代码的存在,会直接跳过访问这个节点。

另外,若有多个起始状态的bfs出现了tle,可能的原因是:队列中的起始状态有重复的,不妨试试没有重复时可不可以度过难关。做leetcode::934::最短的桥时就因为这种原因tle了

dfs时传入了第一个参数。这时就像下棋选择了走的第一步。接着dfs会遍历所有可能的情况。就像只确定下棋的第一步时,之后不同走法可能会走到同一位置一样,dfs也会多次到达同一位置。

因此若只需要到达某个位置一次,则用于一个dfs函数外的数组vis记录访问过的,访问过的就vis[x][y]=1。就算某次递归栈到达了某个地方,但因为这个地方曾经被访问过,进而从这个地方开始的所有其他可能也都曾被访问过,那么就无需再次访问这个地方,这次dfs直接return。

若并非只需要到达某个位置,而是想要知道有多少种到达目标位置的方式。那么标记的方式应该是:在进入dfs函数时令vis[x][y]=1, 在退出dfs时令vis[x][y]=0,通过这种方式避免dfs在一次访问中重复访问某个点。


对bfs进行思考时,用一个长宽为2的地图进行思考。