1206-BUT We Need a Diagram

問題概要

木を図示せよ.
ただし出来る限りハイフンの数が少なくなるようにすること.

解法

再帰的に木を構成していく

実装(C++)

#include <cstring>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
#define REP(i,x)for(int i=0;i<(int)x;i++)
vector<string> input;
string::iterator it;
void read_testcase(){
	string in;
	char _in[10000];
	while(~scanf("%s",_in))
		in=in+string(_in);
	in[in.size()-1]=';';
	while(!in.empty()){
		input.push_back(in.substr(0,in.find(';')));
		in=in.substr(in.find(';')+1);
	}
}
struct Node{
	char label;
	Node* left,*right;
	Node(){
		left=0;
		right=0;
	}
};
vector<Node> stock;
Node* parse(){
	stock.push_back(Node());
	Node *now=&stock.back();
	now->label=*it;
	it++;
	if(*it=='('){
		it++;
		now->left=parse();
		if(*it==','){
			it++;
			now->right=parse();
		}
		it++;
	}
	return now;
}
Node* root;

int where(const vector<string> &map){
	for(int i=0;i<(int)map[(int)map.size()-1].size();i++){
		if(isalpha(map[(int)map.size()-1][i]))return i;
	}
	cerr<<"不正なデーターです"<<endl;
	exit(-1);
}
vector<string> trim(vector<string> &map){
	int min_x=99999,max_x=-999999;
	REP(y,map.size()){
		REP(x,map[y].size()){
			if(map[y][x]!=' '){
				min_x=min(min_x,x);
				max_x=min(max_x,x+1);
			}
		}
	}
	vector<string> res;
	REP(y,map.size()){
		res.push_back(map[y].substr(min_x,max_x-min_x));
	}
	return res;
}
void show(const vector<string> &map){
	REP(y,map.size()){
		REP(x,map[y].size()){
			bool endline=true;
			REP(tx,map[y].size()){
				if(tx>=x){
					if(map[y][tx]!=' ')endline=false;
				}
			}
			if(endline)break;
			cout<<map[y][x];
		}
		cout<<endl;
	}

}
vector<string> merge(const vector<string> &l,const vector<string> &r,int d){
	int mergin=100;
	vector<string> ret(max(l.size(),r.size()),string(mergin+max(l[0].size()+r[0].size()-d,max(r[0].size(),l[0].size())),' '));
	REP(y,l.size()){
		REP(x,l[0].size()){
			if(l[(int)l.size()-1-y][x]!=' ')ret[(int)ret.size()-1-y][mergin+x]='$';
		}
	}
	REP(y,r.size()){
		REP(x,r[0].size()){
			int nx=mergin+l[0].size()+x-d,ny=(int)ret.size()-1-y;
			if(r[(int)r.size()-1-y][x]==' ')continue;//何もおかない
			if(ret[ny][nx]=='$')return vector<string>();
			if(nx&&ret[ny][nx-1]=='$')return vector<string>();
			//置いた上や下に何かがあったら駄目
			if(ny&&ret[ny-1][nx]=='$')return vector<string>();
			if(ny<(int)ret.size()-1&&ret[ny+1][nx]=='$')return vector<string>();
			ret[ny][nx]=r[(int)r.size()-1-y][x];
			if(nx<=0)return vector<string>();
		}
	}
	REP(y,l.size()){
		REP(x,l[0].size()){
			if(l[(int)l.size()-1-y][x]!=' ')ret[(int)ret.size()-1-y][mergin+x]=l[(int)l.size()-1-y][x];
		}
	}
	return trim(ret);
}
vector<string> solve(Node node){
	vector<string> res;
	if(node.left==0){
		//type 0
		string tmp;
		tmp.push_back(node.label);
		res.push_back(tmp);
		return res;
	}else if(node.right==0){
		vector<string> ret=solve(*node.left);
		int x=where(ret);
		int W=ret[0].size();
		string tmp(W,' ');
		tmp[x]='-';
		ret.push_back(tmp);
		tmp[x]=node.label;
		ret.push_back(tmp);
		return ret;
	}else{
		vector<string> left=solve(*node.left);
		vector<string> right=solve(*node.right);
		vector<string> res,ret;
		for(int d=-100;;d++){
			//cout<<"<start>"<<endl;
			ret=merge(left,right,d);
			//cout<<"<end>"<<endl;
			if(ret.empty())break;
			res=ret;
		}
		//cout<<res.empty()<<endl;
		string tmp=string(res[0].size(),' ');
		bool flag=false;
		int s=99999,e=-100000;
		REP(i,tmp.size()){
			if(flag==false&&res[res.size()-1][i]!=' '){
				flag=true;
				if(flag){
					tmp[i]='-';
					s=min(s,i);
					e=max(s,i);
				}
			}else{
				if(flag){
					tmp[i]='-';
					s=min(s,i);
					e=max(s,i);
				}
				if(flag==true&&res[res.size()-1][i]!=' ')flag=false;
			}
		}
		res.push_back(tmp);
		tmp=string(res[0].size(),' ');
		tmp[(s+e)/2]=node.label;
		res.push_back(tmp);
		//cout<<"!"<<endl;
		return res;
	}
	return vector<string>();
}

int main() {
	read_testcase();
	for(int tc=0;tc<(int)input.size();tc++){
		cout<<tc+1<<":"<<endl;
		it=input[tc].begin();
		stock.clear();
		stock.reserve(10000);
		root=parse();
		show(solve(*root));
	}
	return 0;
}