poj 1009

刺骨的言语ヽ痛彻心扉 2021-11-02 00:46 364阅读 0赞

参考自大神思路:POJ 1009
首先,暴力必挂,这是题目的善意提醒。
于是,一直在想不暴力的各种判断计算方法,关于各种跳跃移动,后来都无奈想用STL。原谅我的蒟蒻。
再然后就思维混乱了。于是看网上各位大神的解题报告。很神奇的一个搞法。瞬间被震惊。发现了一个道理,有时候从这个角度搞不通的时候,换一个更直接的角度往往一下就搞通了。是的。
首先可以看出来,这个最终的答案中,肯定会有某些连续段,答案是不变的,这些连续段又和原图有关。我自己的思路就是,先找出在原图的某一连续段中,答案值可能改变的几个像素(做标记),再一次次跳跃到这几个像素中计算它们的答案值,但是问题就是,怎么样的像素才是需要计算的像素。
如图的一个map:
在这里插入图片描述

第一个x显然是需要标记的。然后,可以直接跳跃到第4个x,因为此时它的周围多了一个z,答案可能改变,而第二、三个x显然答案和第一个是一样的。再然后,y的第一个也肯定要标记,因为主体变了。然后到了坐标为(2,3)的y,它需要标记是因为它的周围多了一个m。于是以此类推完成。虽然这个搞法看似可以,但这么多的细节要考虑,况且格子数是10^9,以我的水平注定挂。该怎么办呢。在看了各位大神的题解之后,发现其实我只要把需要标记的格子标记出来,并且把每一连续段的分段画出来,就可以发现很神奇的东西:
在这里插入图片描述

紫色标注的都是要标记的格子,红色边框的代表这一个连续段的起始格。我们可以发现,每个连续段的起始格,都是要标记的格子,同时,每个要标记的格子,都是一个连续段起始格的周围8个格子中的一个。所以,改进的搞法就很清楚了:只需要一个个枚举每个连续段的起始格,并计算它和它四周8个格子的答案值,最后统计答案的时候按照位置先后排序,答案中相同的连续段就合并。因为最多只有1000个连续段,所以不管是时间还是空间都不会超。

注意的细节:最后一个位置也为标记的格子。(有关代码在代码行63行)

在这里插入图片描述
为什么最后一个格子是特殊情况?拿上面这个为例子:红色边框的为连续段的起始格,绿色背景的为标注的格子(没考虑最后一个格子)
输入为:
5
10 9
20 11
0 0

如果没有考虑最后一个格子也为标记格子的情况,则有错误输出:
5
0 3
10 17
0 0

考虑最后一个格子的情况,则有正确输出:
5
0 3
0 3
10 12
0 5
0 0

大家可以好好考虑上面这个例子

上代码:

  1. #include<iostream>
  2. #include<cmath>
  3. #include<algorithm>
  4. const int maxn=1005;
  5. using namespace std;
  6. int width,tot;
  7. struct pix
  8. {
  9. int pos;
  10. int ans;
  11. }outmap[maxn*8];//记录每个起始格及其8个方向
  12. int intmap[maxn][2];//[0]存数值,[1]存长度
  13. int cmp(struct pix p1,struct pix p2)
  14. {
  15. return p1.pos<p2.pos;
  16. }
  17. int getshu(int p)
  18. {
  19. int po=0,i=0;
  20. while(po<=p)
  21. {
  22. po+=intmap[i++][1];
  23. }
  24. return intmap[i-1][0];
  25. }
  26. int getans(int p)
  27. {
  28. int r=p/width;
  29. int c=p%width;
  30. int ans=0,num=getshu(p);
  31. for(int i=r-1;i<=r+1;i++)
  32. {
  33. for(int j=c-1;j<=c+1;j++)
  34. {
  35. int tpos=i*width+j;
  36. if(j<0||i<0||j>=width||tpos>(tot-1)||tpos==p)
  37. continue;
  38. int tmp1=abs(num-getshu(tpos));
  39. if(tmp1>ans) ans=tmp1;
  40. }
  41. }
  42. return ans;
  43. }
  44. int main()
  45. {
  46. while(cin>>width&&width!=0)
  47. {
  48. int num,len,k=0;tot=0;//tot是元素个数
  49. while(cin>>num>>len)//录入所有的起始格
  50. {
  51. if(num==0&&len==0)
  52. break;
  53. intmap[k][0]=num;
  54. intmap[k++][1]=len;
  55. tot+=len;
  56. }
  57. //for(int i=0;i<k;i++)
  58. // cout<<intmap[i][0]<<" "<<intmap[i][1]<<endl;
  59. //cout<<k<<endl<<tot<<endl;
  60. //开始处理
  61. //cout<<getans(10995)<<endl;
  62. int post=0,p=0;//pos为起始格的位置 ,p为记录outmap个数
  63. for(int i=0;i<=k;i++)//遍历所有的起始格!!!**要考虑最后一个也为标记格子,就要是<=k,而不是<k,为什么是这样,自己拿上面那个例子举例**
  64. {
  65. int r=(post)/width;
  66. int c=(post)%width;
  67. //cout<<r<<" "<<c<<endl;
  68. //枚举8个方向
  69. for(int j=r-1;j<=r+1;j++)
  70. {
  71. for(int z=c-1;z<=c+1;z++)
  72. {
  73. int tpos=j*width+z;
  74. if(j<0||z<0||z>=width||tpos>(tot-1))
  75. continue;
  76. //没有出界
  77. outmap[p].pos=tpos;
  78. outmap[p++].ans=getans(tpos);
  79. //cout<<tpos<<" "<<getans(tpos)<<endl;
  80. }
  81. }
  82. //更新post
  83. post+=intmap[i][1];
  84. }
  85. //将标记格排序 :按位置从小到大排序
  86. sort(outmap,outmap+p,cmp);
  87. //for(int i=0;i<k;i++)
  88. // printf("%d %d\n",outmap[i].pos,outmap[i].ans);
  89. struct pix tmp=outmap[0];
  90. cout<<width<<endl;
  91. for(int i=1;i<p;i++)
  92. {
  93. if(outmap[i].ans==tmp.ans)
  94. continue;
  95. printf("%d %d\n",tmp.ans,outmap[i].pos-tmp.pos);
  96. tmp=outmap[i];
  97. }
  98. printf("%d %d\n",tmp.ans,tot-tmp.pos);
  99. printf("0 0\n");
  100. }
  101. printf("0\n");
  102. return 0;
  103. }

发表评论

表情:
评论列表 (有 0 条评论,364人围观)

还没有评论,来说两句吧...

相关阅读

    相关 POJ1009解题报告

    保送之后都是项目的事情,一直没有时间写acm题,今天刚好礼拜六尝试着继续之前的工作,争取以后每周能够写上1-2个poj。很久没写算法题感觉自己的智商已经完全不够用了。 说说这

    相关 Hdu1009 贪心

    解题报告题意:题目真长,看不怎么懂。就是说有n个房间,每个房间都有avaBean这种东西,每个房间东西的质量为Ji,需要支付的钱为Fi。问在总钱数为M的前提下,最多可以得到av

    相关 1009. 说反话 (20)

    给定一句英语,要求你编写程序,将句中所有单词的顺序颠倒输出。 输入格式:测试输入包含一个测试用例,在一行内给出总长度不超过80的字符串。字符串由若干单词和若干空格组成,其中单

    相关 PAT乙级1009

    1009 说反话 (20)(20 分) 给定一句英语,要求你编写程序,将句中所有单词的顺序颠倒输出。 输入格式:测试输入包含一个测试用例,在一行内给出总长度不超过80的字符

    相关 1009 说反话

    题目描述 给定一句英语,要求你编写程序,将句中所有单词的顺序颠倒输出。 输入格式: 测试输入包含一个测试用例,在一行内给出总长度不超过 80 的字符串。字符串由若

    相关 poj 1009

    参考自大神思路:[POJ 1009][] 首先,暴力必挂,这是题目的善意提醒。 于是,一直在想不暴力的各种判断计算方法,关于各种跳跃移动,后来都无奈想用STL。原谅我的

    相关 cf 1009E

    如何看待某cf2000分选手不会一道tag1900的题? 难。 考虑每段距离的贡献, a\[i\]出现在位置j上,当且仅当j-i休息,并且中间的都不是休息的。