漢文の文字数、読む順番を入力すると、各漢字につく返り点(レ点、一二点、ハイフン)を改行区切りで表示します。
#include <iostream>
#include <iomanip>
#include <vector>
#include <string>
using namespace std;
string moji[8][10]={{"上","中","下"},
{"一","二","三","四","五","六","七"},
{"上","下"},
{"甲","乙","丙","丁","戊","己","庚","辛","任","癸"},
{"天","地","人"},
{"元","亨","利","貞"},
{"春","夏","秋","冬"},
{"木","火","土","金","水"}
};
struct OneTwo
{
int level; //一、二、三の違い
int nest; //一、上、甲の違い
};
typedef vector<int> VecInt;
typedef vector<OneTwo> VecOneTwo;
void solve(int n ,VecInt turn_to_point ,VecInt next_point ,VecOneTwo *edge);
void PrintVector(VecInt vec);
void SetReadOrderToPoint(VecInt *turn_to_point ,VecInt next_point ,int n);
int main(){
//宣言
VecInt turn_to_point; //添え字:読む順番 値:場所
VecInt next_point; //添え字:場所 値:次の場所
int n; //漢文の文字数
VecOneTwo edge; //添え字:場所 値:一二点系の返り点の種類
//入力
{
cout <<"漢文の文字数を入力"<<endl;
cin >> n;
next_point.resize(n);
cout << "漢文の読む順番を半角スペースで区切って入力"<<endl;
for (int i = 0; i < n; i++)
{
int a;
cin >> a;
next_point[a-1] = i;
}
}
//初期化
{
for (int i = 0; i < n; i++){
OneTwo start;
start.level = -1;
start.nest = -1;
edge.push_back(start);
}
SetReadOrderToPoint(&turn_to_point, next_point, n);
}
solve(n ,turn_to_point ,next_point ,&edge);//計算
//表示
{
for (int i = 0; i < n; i++)
{
//レ点
if (i != n && turn_to_point[i+1] == -1) //次に進む場所が一つ前なら
cout <<"レ";
else
cout <<" ";
//一二点系返り点
if (edge[i].nest != -1) //nestが初期値と違ったら
{
cout << moji[ edge[i].nest ][ edge[i].level ]; //一二点系返り点表示
if (turn_to_point[i] == 1) //一二点の後、行き先が一つ下なら
cout <<"|"; //ハイフン表示
else
cout <<" ";
}
else
{
cout <<" ";
}
cout<<":"<<endl;
}
}
return 0;
}
void solve(int n ,VecInt turn_to_point,VecInt next_point,VecOneTwo *edge){
//初期化
int level = 0;
int nest = 1;
VecInt check_same_nest;
for (int i = 0; i < n; i++)
{
if (turn_to_point[ next_point[i] ] >= -1)//返り点が連続しなかったら
{
check_same_nest.clear(); //データオール初期化
level = 0;
nest = 1;
continue;
}
//一、上などだけがここから下の処理を受ける
check_same_nest.push_back( next_point[i] ); //通った点を記録
for (int now = next_point[i]-1; now > next_point[i+1]; now--) //返り点の間に別の返り点があるかチェック
{
if ( (*edge)[now].nest >= nest) //自分以上にnestの高いのがいれば
{
nest = (*edge)[now].nest + 1; //それ+1を代入
}
}
if ( (*edge)[ check_same_nest[0] ].nest < nest) //昔のネストが今より低かった時
{
for (int i = 0; i < check_same_nest.size(); i++)
{
(*edge)[ check_same_nest[i] ].nest = nest; //過去の地点に今のネストを代入
}
}
//上下点処理
{
if (nest == 2)
{
switch (level)
{
case 1: //返り点が計3つになったら
nest = 0; //上中下点へ(上点は変わらないので無視)
break;
case 2: //返り点が計4つになったら
nest = 3; //過去のもさかのぼって甲乙点へ
for (int i = 0; i < 2; i++)
{
(*edge)[ check_same_nest[i] ].nest=3;
}
break;
}
}
}
OneTwo now;
now.level = level; //level引き継ぎ
now.nest = nest; //nestを引き継ぎ
(*edge)[ next_point[i] ] = now; //答えに代入
now.level++;
(*edge)[ next_point[i+1] ] = now; //返る場所にも返り点をつける ex:二,下
}
}
void SetReadOrderToPoint(VecInt *turn_to_point, VecInt next_point, int n)//read_order_to_pointを初期化
{
(*turn_to_point).resize(n);
for (int i = 0; i < n - 1; i++)
{
(*turn_to_point)[ next_point[i] ] = next_point[i+1] - next_point[i];//相対距離を代入
}
(*turn_to_point)[ next_point[n-1] ] = 0;//終点には0を代入
}
void PrintVector(VecInt vec) //与えられた配列の全要素を表示
{
for(int i = 0; i < vec.size(); i++)cout <<setw(2) <<internal <<vec[i] <<endl;
cout <<endl;
}