问题描述
画一个等边三角形,把三边的中点连接起来,得到四个三角形,把它们称为T1,T2,T3,T4,如图1。把前三个三角形也这样划分,得到12个更小的三角形:T11,T12,T13,T14,T21,T22,T23,T24,T31,T32,T33,T34,如图2。把编号以1,2,3结尾的三角形又继续划分……最后得到的分形称为Sierpinski三角形。
如果B不包含A,且A的某一条完整的边是B的某条边的一部分,则我们说A靠在B的边上。例如T23靠在T24和T4上,但不靠在T32上。给出Spierpinski(注:原文如此)三角形中的一个三角形,找出它靠着的所有三角形。
输入格式
输入仅一行,即三角形的编号,以T开头,后面有n个1到4的数字。仅最后一个数字可能为4。
输出格式
输出每行一个三角形编号,按字典序从小到大排列。
样例输入 1
T312
样例输出 1
T314
T34
T4
样例输入 2
T123212321
样例输出 2
T123212324
T12321234
T1232124
提示
50%的数据满足:1<=n<=5
100%的数据满足:1<=n<=50
其实这道题刚开始我看的时候以为是道分治题,因为在不断分形嘛,但是后来发现其实它每一次分形都是有规律的。
我们不妨再画下一组出来,草稿本上画一画是一个好习惯。
在这里我就直接把我电脑上画的丑图放出来,解释一下规律。
从图上,我们不难找出如下规律:
- 当输入的序列尾数为4的时候,我们只需要将它周围的三个三角形输出来即可。而周围的三个三角形满足规律:将输入的序列队尾分别改成1,2,3即可。
- 当输入的序列尾数不为4的时候,我们可以用以下方法来求解:从后往前枚举每一位数i,若该数字没有出现过,则标记mark[i]==true,并将i以及后面的数位一起改为i。如样例输入1,T312(if(mark[2]==false))则变为T314;接着讨论mark[1],mark[3],均没有出现过,则变为T34,T4
有了这个规律,做这个题就十分简单了。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char s[100];
int ans[100],len;
int temp;
int cnt=1;
bool mark[10];
int main()
{
scanf("%s",&s);
len=strlen(s)-1;
if (s[len]=='4')//讨论最后位数为4的情况
{
for(int i=1;i<=3;++i)
{
printf("T");
for (int j=1;j<len;++j)
printf("%c",s[j]);
printf("%d\n",i);
}
}
else //如果!=4
{
ans[1]=len-1;
for (int i=len-2;i>=0;--i)
{
mark[s[i+2]-'0']=true;//标记过已经出现过
if(!mark[s[i+1]-'0'])cnt++,ans[cnt]=i;
}
for(int i=1;i<=cnt;++i)
{
printf("T");
for (int j=1;j<=ans[i];++j) printf("%c",s[j]);
printf("%d\n",4);
}
}
}