第八章例题 UVa11134 Fabled Rooks

/*SE:wn------王宁*/

首先是对行列不相关的理解,只要行列都各自满足不相关即可——好像和没说一样,但是如果不能理解这个也不能理解剩下的做法,一定要先想清楚的确可以用一维的方法解题。

接下来是对那个solve函数的for循环解读——贪心思想,然后是做这道题目遇到的bug以及修复方法

解读——贪心思想
/*

1. 未被使用过
2. 能在前端满足包含条件 
3. 后端要尽可能靠近当前点,因为后端不那么靠前的区间既然前端满足当前点,那么他在后面的点也是能满足前端的条件,
而且相对于选择的这个区间它更有机会满足后面的点的选择条件——贪心
4. 如果出现当前选择区间的后端小于当前点,那么意味着这个区间没有被选择,这也是不合题意的——对应的车没有被放置
出现这种情况的原因只可能是前一个点它没有被选择(后端的值等于前一个点),因为被选择的都是后端大于等于当前点的区间,
能把这个区间排除掉——根据后端要尽可能靠近当前点的原则,把这个区间排除掉的只可能是后端也在前一个点的区间——而它被先选择了
——被选择成功才有机会进行下一个点的选择,所以能挤掉这个没被选择的区间的区间的后端也在前一个点上
在前一个点没有被选择,它之后也都不可能再被选择了
如果改成if(c[i] < 0 && b[i] < minb && col >= a[i] && col<=b[i]) 以及 if(rook < 0 ) 会更加直观一些,只不过判断次数会变多
5. 而点按照1-n的顺序从前往后选择区间,保证了……这个贪心策略的可行性?反正从1-n也是很重要的*/

 

遇到的bug以及修复方法

关于初始化数值

1.大家是不是非常习惯用memset?

但是在函数中,你传的只是数组地址,如果写成memset(c,-1,sizeof(c));,那么只有前两个会赋成-1,而正确的写法是memset(c,-1,sizeof(int)*(n+1));。

fill的话因为强制要求是传首尾地址所以不会出现这个问题——当然fill突破了memset只能设置0、-1、0x3f的限制,值得记住并应用。

2.如果你是按照1-n而不是0-(n-1)来记录信息的,那么要小心前开后闭的性质——fill(c+1,c+n,-1)只能将1-(n-1)赋成-1。

而这个不是-1会导致缺少一个rook能参与区间和点的配对(其实就是最后一个rook,它的c[i]值是0,永远不会被考虑),那么就永远都是printf("IMPOSSIBLE\n");——即使你写的和原程序一样而在这里写错……

好了,贴上刘汝佳大神的源码,建议自己重写,重写也需要对题意的深刻理解的,有助理清思路:

// UVa11134 Fabled Rooks
// Rujia Liu
#include<cstdio>
#include<cstring>
#include <algorithm>
using namespace std;

// solve 1-D problem: find c so that a[i] <= c[i] <= b[i] (0 <= i < n)

bool solve(int *a, int *b, int *c, int n) {
  fill(c, c+n, -1);
  for(int col = 1; col <= n; col++) {
    // find a rook with smalleset b that is not yet assigned
    int rook = -1, minb = n+1;
    for(int i = 0; i < n; i++)
      if(c[i] < 0 && b[i] < minb && col >= a[i]) { rook = i; minb = b[i]; }
    if(rook < 0 || col > minb) return false;
    c[rook] = col;
  }
  return true;
}

const int maxn = 5000 + 5;
int n, x1[maxn], y1[maxn], x2[maxn], y2[maxn], x[maxn], y[maxn];

int main() {
  while(scanf("%d", &n) == 1 && n) {
    for (int i = 0; i < n; i++)
      scanf("%d%d%d%d", &x1[i], &y1[i], &x2[i], &y2[i]);
    if(solve(x1, x2, x, n) && solve(y1, y2, y, n))
      for (int i = 0; i < n; i++) printf("%d %d\n", x[i], y[i]);
    else
      printf("IMPOSSIBLE\n");
  }
  return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值