洛谷-提高历练地

哎呀好几天没写POI题解了 (>﹏<)

看着摇曳不定的小旗子深深惶恐

打算开始肝洛谷试炼场的提高分区了【对我就是这么菜…

  • 搜索Ex

比暴搜不错得多的题

洛谷P1514 引水入城

拆成两问来看 第一问只要从湖边的城市(简称湖城)开始搜索就可以了

第二问的faulse项

用dfs剩的vis统计一下沙漠边缘有哪些点(简称沙城)没被搜到的

true项 蒟蒻一开始想状压

当然 n <= 500 【黑线

后来画了个等高线地形图【划掉

发现如果每个沙城都能有水喝【即true项

每个湖城管辖的沙城都是连续的区间

现在问题就变成了 至少用多少个区间覆盖整个区间

当然这问题长得很DP 但有个贪心更优

借用一位神犇的例子

m为10
N = 7:[1,5]、[1,6]、[3,6]、[1,7]、[6,9]、[9,10]、[7,9]。

先把每个区间(都是闭区间)排序 左区间小的优先

[1,5]、[1,6]、[1,7]、[3,6]、[6,9]、[7,9]、[9,10]

我们从1开始

选择每个区间的代价都是1 选择右区间大的显然更优

所以取[1, 7]

现在左区间小区等于7的区间 在小于等于7的部分已经被覆盖 所以无效了

为使区间连续 我们找(左区间小于等于8的区间)中(右区间最大的区间)

okk

最后附一句 如果找到一个地方 (可用最大右区间)小于(上一个取的区间的左区间)

 1 inline void dfs(int x, int y){
 2      node[x][y].vis = 1;
 3      if(x < 1 || x > n || y < 1 || y > m) return ;
 4      for(int i = 0; i <= 3; i++){
 5          int sx = x + move[i][0], sy = y + move[i][1];
 6          if(node[sx][sy].w < node[x][y].w){
 7              if(!node[sx][sy].vis){
 8                  dfs(sx, sy);                              
 9              }        
10              node[x][y].l = min(node[sx][sy].l, node[x][y].l);
11              node[x][y].r = max(node[sx][sy].r, node[x][y].r);
12          }         
13      }
14 }
dfs部分
 1     for(int i = 1; i <= m; i++)
 2        a[i] = (A){node[1][i].l, node[1][i].r};
 3     sort(a + 1, a + m + 1, cmp);
 4     int i = 1, j = 1, ans = 0;
 5     while(j <= m){
 6         int k = j;
 7         while(a[i].l <= k){
 8             j = max(j, a[i].r);
 9             i++;             
10         }
11         j++;        
12         ans++;
13     }
14     printf("1\n%d", ans);
贪心部分

洛谷P1242 新汉诺塔

吐槽玄学数据…

明明能一次A的wwww【委屈

 1 void dfs(int cur, int from, int to, bool flag){
 2      //cur表示当前要移动的圆盘大小 from表示它在的位置 to表示它要移动到的地方 
 3      //flag = 1 表示cur是在进行主操作的点 flag = 0表示cur是为了移动另一个圆盘而移动的 
 4     if(from == to){
 5         if(cur > 1) dfs(cur - 1, s[cur - 1], flag ? t[cur - 1] : to, flag);
 6         /*
 7         当要移动的盘已经在它的目标位置上
 8         如果flag = 1 那么它的主操作已经被完成 需要将主操作传递到下一个级别的圆盘上 
 9         flag = 0 那么要把下一个级别的圆盘从它的位置上移动到无关的杆子上 
10         */
11         return ;        
12     }     
13     if(cur > 1) dfs(cur - 1, s[cur - 1], 6 - from - to, 0); 
14     //把比它小的所有盘都移到无关的杆子上 
15     printf("move %d from %c to %c\n", cur, turn(from), turn(to));
16     s[cur] = to; ans++;
17     //移动后 当前盘已经在目标位置上 与from == to的操作一致 
18     if(cur > 1) dfs(cur - 1, s[cur - 1], flag ? t[cur - 1] : to, flag);
19 }
20 /*
21 汉诺塔的框架:
22 将主操作从大盘向小盘传递 
23 移动一个盘的最优策略是把它上面的盘都移到无关杆上
24 注意的点:
25 flag的传递
26 起点终点的选择
27 输出格式
28 结束条件(cur == 1) 
29 */ 

 

猜你喜欢

转载自www.cnblogs.com/hjmmm/p/9207829.html
今日推荐