CCF2015-12-3画图
Posted awangkuo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CCF2015-12-3画图相关的知识,希望对你有一定的参考价值。
第1行有三个整数m, n和q。m和n分别表示画布的宽度和高度,以字符为单位。q表示画图操作的个数。
第2行至第q + 1行,每行是以下两种形式之一:
? 0 x1 y1 x2 y2:表示画线段的操作,(x1, y1)和(x2, y2)分别是线段的两端,满足要么x1 = x2 且y1 ≠ y2,要么 y1 = y2 且 x1 ≠ x2。
? 1 x y c:表示填充操作,(x, y)是起始位置,保证不会落在任何已有的线段上;c 为填充字符,是大小写字母。
画布的左下角是坐标为 (0, 0) 的位置,向右为x坐标增大的方向,向上为y坐标增大的方向。这q个操作按照数据给出的顺序依次执行。画布最初时所有位置都是字符 .(小数点)。
本题自身的逻辑并不困难,在写出模拟改动之后,出了两个小问题,一次80,一次90,而且都不是第一时间找到问题所在,改动了很多次才通过,值得警醒。
第一个bug,答案错误,80分,那么是哪里错了呢,前面的样例基本正确且通过,至80分样例开始错误,一定是哪个特殊情况没有考虑到,这时候检查代码没有发现问题之后,最好重新读题,很可能是某句话理解有误。细读之后发现这句“如果一条水平线段和一条竖直线段在某个位置相交,则相交位置用字符 + 代替。”在我之前的理解之中,添加+号是在-添加时判断其上下有无|,有则+,无则-,|号同理。
这个理解是错的,题意是说如果在某位置相交,才会出现+号,那么如果|号刚好添加到了-号的上位,但并不相交,按我原来代码,是要出现+号的,自然大错特错。
第二个bug,时间超时,90分,说实话这个问题还是我第一次在ccf中遇到,ccf大多数时间都只有1s,拿出普通算法早已足够,在此问题出现之后,我多次改动,甚至修改了容器和字符串的初始化操作,可并未出现理想的有效结果,这使我意识到优化初始化并不能带来什么,那么,我的字母判断函数呢,我将自己定义的字母判断函数加了个引用,也无效,用系统自带的字母判断函数会不会效果好点?事实证明也是徒劳的。那么问题应该是出现在了算法的优化上。画线段本身逻辑简单,问题不在这里,在用队填充的过程中,我用了自己写的vector队,每次遍历都是j++,且满足条件后放到队尾,初看之下并无大碍,所以怎么也检查不出来,就试着去阅读满分的代码,看他们的逻辑结果,在这过程中福至心头,想到我的队列情况如果是第一行AA 第二行AB,从B开始填充,左上角的A竟然多次入队判断,非常浪费时间,指数级消耗无用判断,所以在这里也优化了一次,优先判断V【y】【x】是否为c,如果是,那么j++,直接continue,之前就访问过这里,进入下一次循环即可。如果不是,才有了将其改为c,并且进入队资格判断。至此,提交之后的代码是100分,不再超时。还有一个有意思的细节是,分别用了我的引用判断字母函数,和标准库里的字母函数,我自己的居然是900ms,标准库中984ms,那么,这多出来的84ms是哪里的问题呢?初步理解为isalpha(int c),用的是赋值,没用引用。也许是其设计之初针对一个字符的赋值即可并不需要引用?
转到其定义如下:
template<typename _CharT> inline bool isalpha(_CharT __c, const locale& __loc) { return use_facet<ctype<_CharT> >(__loc).is(ctype_base::alpha, __c); }
恐怕我要到模板部分深入探索之后才能再下定论。
整体代码如下:
#include <iostream> #include <vector> #include <string> using namespace std; bool isalp(char &c) { if(c-‘a‘>=0 && c-‘a‘<26) return true; if(c-‘A‘>=0 && c-‘A‘<26) return true; return false; } int main() { // 第1行有三个整数m, n和q。m和n分别表示画布的宽度和高度,以字符为单位。q表示画图操作的个数。 // 第2行至第q + 1行,每行是以下两种形式之一: // ? 0 x1 y1 x2 y2:表示画线段的操作,(x1, y1)和(x2, y2)分别是线段的两端,满足要么x1 = x2 且y1 ≠ y2,要么 y1 = y2 且 x1 ≠ x2。 // ? 1 x y c:表示填充操作,(x, y)是起始位置,保证不会落在任何已有的线段上;c 为填充字符,是大小写字母。 // 画布的左下角是坐标为 (0, 0) 的位置,向右为x坐标增大的方向,向上为y坐标增大的方向。这q个操作按照数据给出的顺序依次执行。画布最初时所有位置都是字符 .(小数点)。 int m,n,q; cin>>m>>n>>q; string t(m,‘.‘); vector<string> v(n,t); for(int i=0;i<q;i++) { int mod; cin>>mod; if(mod==0) { int x1,y1,x2,y2; cin>>x1>>y1>>x2>>y2; if(y1==y2) { int y=y1; int minx=min(x1,x2); int maxx=max(x1,x2); for(int x=minx;x<=maxx;x++) { if(v[y][x]==‘|‘) v[y][x]=‘+‘; else if(v[y][x]!=‘+‘) v[y][x]=‘-‘; } } else if(x1==x2) { int x=x1; int miny=min(y1,y2); int maxy=max(y1,y2); for(int y=miny;y<=maxy;y++) { if(v[y][x]==‘-‘) v[y][x]=‘+‘; else if(v[y][x]!=‘+‘) v[y][x]=‘|‘; } } } else{ //填充函数,是否用到队列 int x3,y3; char c; cin>>x3>>y3; cin>>c; //创建一个队列,填充式补c vector<vector<int>> q; vector<int> temp; temp.push_back(x3); temp.push_back(y3); q.push_back(temp); temp.clear(); int j=0; while(j!=q.size()) { int x=q[j][0]; int y=q[j][1]; if(v[y][x]!=c) v[y][x]=c; else{ j++; continue; } if(y+1<n && v[y+1][x]!=c && (v[y+1][x]==‘.‘ || isalpha(v[y+1][x]))) { temp.push_back(x); temp.push_back(y+1); q.push_back(temp); temp.clear(); } if(y-1>=0 && v[y-1][x]!=c && (v[y-1][x]==‘.‘ || isalpha(v[y-1][x]))) { temp.push_back(x); temp.push_back(y-1); q.push_back(temp); temp.clear(); } if(x-1>=0 && v[y][x-1]!=c && (v[y][x-1]==‘.‘ || isalpha(v[y][x-1]))) { temp.push_back(x-1); temp.push_back(y); q.push_back(temp); temp.clear(); } if(x+1<m && v[y][x+1]!=c && (v[y][x+1]==‘.‘ || isalpha(v[y][x+1]))) { temp.push_back(x+1); temp.push_back(y); q.push_back(temp); temp.clear(); } j++; } q.clear(); } } // for(int i=0;i<n;i++) // { // v2.push_back(v[i]); // } for(int i=v.size()-1;i>=0;i--) { cout<<v[i]<<endl; } return 0; }
以上是关于CCF2015-12-3画图的主要内容,如果未能解决你的问题,请参考以下文章