《黑书》例题:三色多边形
http://acm.timus.ru/problem.aspx?space=1&num=1181
这是一道递归题?倒不如说是模拟题,不知道是哪个(混蛋)学长和我说的,模拟题是最容易,容易个毛线........好吧,废话不说了
思路:黑书上有它的思路P20,但我还是说说自己的想法吧。先是按照黑书的思路,要是可以将一个n边形的问题规模转化为n-1,n-2......3,也就是说可以讲符合条件的三角形切掉,然后再去找下一个符合条件的三角形,再切掉.......但是有个问题,什么时候不切了??
黑书中描述的很清楚,有一种特殊的情况,三种颜色,有一种颜色只出现一次,那么我们可以以这种颜色为顶点,分切三角形.......例如:
这样,就是递归的结束条件.........我的思路写的很乱,具体的还是请去看黑书的吧......
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; char s[20000]; int a[20000],flag=0,n; int dfs(char s[]) { int r,b,g; r=b=g=0; int len=strlen(s); for(int i=0;i<len;i++) //这是每次都记录R\B\G出现的次数 { if(s[i]=='R') r++; if(s[i]=='B') b++; if(s[i]=='G') g++; } if(r==1) //判断是否只是出现一次 { for(int i=0;i<len;i++) if(s[i]=='R') { int tmp; if(i==len-1) //如果只是出现一次,那么要考虑有那只出现一次的所在位置,可以是0位置,中间位置,和末位置 tmp=1; else tmp=0; for(int j=i-2;j>=tmp;j--) { printf("%d %d\n",a[i]+1,a[j]+1); flag++; } if(i==0) tmp=len-2; else tmp=len-1; for(int j=i+2;j<=tmp;j++) { printf("%d %d\n",a[i]+1,a[j]+1); flag++; } } return 1; //解决完后,你会发现所以情况都考虑了,就需要返回 } else if(b==1) { for(int i=0;i<len;i++) if(s[i]=='B') { int tmp; if(i==len-1) tmp=1; else tmp=0; for(int j=i-2;j>=tmp;j--) //输出对角线 { printf("%d %d\n",a[i]+1,a[j]+1); flag++; } if(i==0) tmp=len-2; else tmp=len-1; for(int j=i+2;j<=tmp;j++) { printf("%d %d\n",a[i]+1,a[j]+1); flag++; } } return 1; } else if(g==1) { for(int i=0;i<len;i++) if(s[i]=='G') { int tmp; if(i==len-1) tmp=1; else tmp=0; for(int j=i-2;j>=tmp;j--) { printf("%d %d\n",a[i]+1,a[j]+1); flag++; } if(i==0) tmp=len-2; else tmp=len-1; for(int j=i+2;j<=tmp;j++) { printf("%d %d\n",a[i]+1,a[j]+1); flag++; } } return 1; } else { int i; for(i=0;i<len-2;i++) //这里,要记着-2......一开始这里木有注意..... if(s[i]!=s[i+1]&&s[i]!=s[i+2]&&s[i+1]!=s[i+2]) { printf("%d %d\n",a[i]+1,a[i+2]+1); //输出可以的对角线 flag++; for(int j=i+1;j<len-1;j++) //将那个对角线里面的点过滤掉,但是不能改变剩下的点的位置和颜色 ,一开始我就是不知道这里怎么实现的 { s[j]=s[j+1]; //看了大神代码之后,就明白了.......就是把那个店过滤,用后面的点覆盖那个点,颜色与位置都做这样的操作 a[j]=a[j+1]; } s[len-1]='\0'; //就是这里,wa了2次.......一定要注意,把点覆盖后,要将它末尾置为结束符 break; } } if(dfs(s)) return 1; return 0; } int main() { while(scanf("%d",&n)>0) { scanf("%s",s); int r=0,b=0,g=0,w=0; int len=strlen(s); if(s[0]==s[len-1]) {printf("0\n"); continue;} //这里wa了一次,第一个字符与最后一个字符是相邻的,但我一开始没有考虑到它们是否相等 for(int i=0;i<len-1;i++) if(s[i]==s[i+1]) { w=1; break; } for(int i=0;i<len;i++) { if(s[i]=='R') r++; if(s[i]=='B') b++; if(s[i]=='G') g++; } if(w==1||r==0||b==0||g==0) //要是R\B\G有为0的,说明肯定有相邻相等的..... { printf("0\n"); continue; } for(int i=0;i<n;i++) a[i]=i; printf("%d\n",n-3); //将多边形分为n-2个三角形,必然要n-3条边 flag=0; dfs(s); } return 0; }
朋友们,虽然这个世界日益浮躁起来,只要能够为了当时纯粹的梦想和感动坚持努力下去,不管其它人怎么样,我们也能够保持自己的本色走下去。