Problem:
Problem D:
Organize Your Train
In the good old Hachioji railroad station located in the west of Tokyo, there are several parking
lines, and lots of freight trains come and go every day.
All freight trains travel at night, so these trains containing various types of cars are settled in
your parking lines early in the morning. Then, during the daytime, you must reorganize cars
in these trains according to the request of the railroad clients, so that every line contains the
“right” train, i.e. the right number of cars of the right types, in the right order.
As shown in Figure 7, all parking lines run in the East-West direction. There are exchange
lines connecting them through which you can move cars. An exchange line connects two ends
of different parking lines. Note that an end of a parking line can be connected to many ends of
other lines. Also note that an exchange line may connect the East-end of a parking line and the
West-end of another.
Cars of the same type are not discriminated between each other. The cars are symmetric, so
directions of cars don’t matter either.
You can divide a train at an arbitrary position to make two sub-trains and move one of them
through an exchange line connected to the end of its side. Alternatively, you may move a whole
train as is without dividing it. Anyway, when a (sub-) train arrives at the destination parking
line and the line already has another train in it, they are coupled to form a longer train.
Your superautomatic train organization system can do these without any help of locomotive
engines. Due to the limitation of the system, trains cannot stay on exchange lines; when you
start moving a (sub-) train, it must arrive at the destination parking line before moving another
train.
In what follows, a letter represents a car type and a train is expressed as a sequence of letters.
For example in Figure 8, from an initial state having a train "
aabbccdee
" 
on line 0 and no trains
on other lines, you can make "
bbaadeecc
" on line 2 with the four moves shown in the figure.
To cut the cost out, your boss wants to minimize the number of (sub-) train movements. For
example, in the case of Figure 8, the number of movements is 4 and this is the minimum.
Given the configurations of the train cars in the morning (arrival state) and evening (departure
state), your job is to write a program to find the optimal train reconfiguration plan.
Input
The input consists of one or more datasets. A dataset has the following format:
x y
p
1
P
1
q
1
Q
1
p
2
P
2
q
2
Q
2
.
.
.
p
y
P
y
q
y
Q
y
s
0
s
1
.
.
.
s
x
-1
t
0
t
1
.
.
.
t
x
-1
x
is the number of parking lines, which are numbered from 0 to
x
-1.
y
is the number of exchange
lines. Then
y
lines of the exchange line data follow, each describing two ends connected by the
exchange line;
p
i
and
q
i
are integers between 0 and
x
- 1 which indicate parking line numbers,
and
P
i
and
Q
i
are either "
E
" (East) or "
W
" (West) which indicate the ends of the parking lines.
Then
x
lines of 
...(truncated)

Submitted solutions:

code_snippet: #include <cmath>
#include <ctime>
#include <cstdio>
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <sstream>
#include <algorithm>
#include <set>
#include <stack>
#include <queue>
#include <string>
#include <vector>
#include <map>
#define maxn 110
#define maxl 1000000000
#define mod 1000000007
using namespace std;

typedef unsigned long long ull;


typedef vector<string> ZT;
typedef set<ZT>::iterator IT;
set<ZT> be[4],en[4];
int ans,n;
int g[100][100];

bool check(int id,const ZT &vv,set<ZT> be[],set<ZT> en[]){
	for(int i=0;i<=id+1;++i){
		if(en[i].count(vv)){
			ans=id+1+i;
			//for(int j=0;j<n;++j)cout<<vv[j]<<endl;
			return true;
		}
		if(be[i].count(vv))return false;
	}
	be[id+1].insert(vv);
	return false;
}

void ex(int id,set<ZT> be[],set<ZT> en[]){
	IT it;
	int i,j,k;
	for(it=be[id].begin();it!=be[id].end();++it){
		ZT v=*it,vv;
		for(i=0;i<n;++i)if(v[i]!="")
			for(j=0;j<n;++j)if(j!=i){
				if(g[i][j]&1){
					vv=v;
					for(k=0;k<v[i].size();++k){
						vv[j].insert(vv[j].begin(),v[i][k]);
						vv[i].erase(0,1);
						if(check(id,vv,be,en))return;
					}
				}
				if(g[i][j]&2){
					vv=v;
					for(k=0;k<v[i].size();++k){
						vv[j].insert(vv[j].end(),v[i][k]);
						vv[i].erase(0,1);
						if(check(id,vv,be,en))return;
					}
				}
				if(g[i][j]&4){
					vv=v;
					for(k=v[i].size()-1;k>=0;--k){
						vv[j].insert(vv[j].begin(),v[i][k]);
						vv[i].erase(vv[i].size()-1,1);
						if(check(id,vv,be,en))return;
					}
				}
				if(g[i][j]&8){
					vv=v;
					for(k=v[i].size()-1;k>=0;--k){
						vv[j].insert(vv[j].end(),v[i][k]);
						vv[i].erase(vv[i].size()-1,1);
						if(check(id,vv,be,en))return;
					}
				}
				
			}
	}
}

bool solve(){
	int m,i,j,temp,x,y;
	string s;
	char c1,c2;
	scanf("%d%d",&n,&m);
	if(n==0 && m==0)return false;
	for(i=0;i<n;++i)
		for(j=0;j<n;++j)g[i][j]=0;
	for(i=1;i<=m;++i){
		scanf("%d%c%d%c",&x,&c1,&y,&c2);
		if(c1=='W'){
			if(c2=='W')temp=1;else temp=2;
		}else {
			if(c2=='W')temp=4;else temp=8;
		}
		g[x][y]|=temp;
		swap(x,y);swap(c1,c2);
		if(c1=='W'){
			if(c2=='W')temp=1;else temp=2;
		}else {
			if(c2=='W')temp=4;else temp=8;
		}
		g[x][y]|=temp;
	}
	for(i=0;i<=3;++i){
		be[i].clear();
		en[i].clear();
	}
	ZT v1,v2;
	v1.clear();
	for(i=0;i<n;++i){
		cin>>s;
		if(s=="-")s="";
		v1.push_back(s);
	}
	be[0].insert(v1);
	//for(int j=0;j<n;++j)cout<<v1[j]<<endl;
	v1.clear();
	for(i=0;i<n;++i){
		cin>>s;
		if(s=="-")s="";
		v1.push_back(s);
	}
	en[0].insert(v1);
	//for(int j=0;j<n;++j)cout<<v1[j]<<endl;
	ans=-1;
	//cout<<"here"<<endl;
	for(i=0;i<=2;++i){
		ex(i,be,en);
		if(ans>0)break;
		//cout<<"look"<<endl;
		ex(i,en,be);
		if(ans>0)break;
	}
	if(ans==-1){
		int y=1,x=0;
		//exit(y/x);
	}
	cout<<ans<<endl;
	return true;
}

int main(){
	while(solve());
	return 0;
}
accuracy: 1
time_ms: 1810
memory_kb: 35196
final_rank: 7

code_snippet: #include <iostream>
#include <vector>
#include <cmath>
#include <numeric>
#include <cfloat>
#include <climits>
#include <algorithm>
#include <iomanip>
#include <queue>
#include <unordered_set>
#include <unordered_map>
#include <string>
#include <tuple>
#include <set>
#include <stack>
#include <array>
enum class Dir {
	East, West
};
constexpr std::array<Dir, 2> all_dir{ Dir::West, Dir::East };
struct End {
	int id;
	Dir dir;
};
std::istream& operator>>(std::istream& is, End& end) {
	char id, dir;
	is >> id >> dir;
	end.id = id - '0';
	end.dir = dir == 'W' ? Dir::West : Dir::East;
	return is;
}
struct ExchangeLine {
	End from, to;
};
struct ParkingLine {
	long long int hash{ 0 }, power{ 1 };
	bool is_empty() const {
		return power == 1;
	}
	void push_east(const int car) {
		hash *= 10;
		hash += car;
		power *= 10;
	}
	void push_west(const int car) {
		hash += power * car;
		power *= 10;
	}
	int pop_east() {
		const auto popped = hash % 10;
		hash /= 10;
		power /= 10;
		return popped;
	}
	int pop_west() {
		power /= 10;
		const int popped = hash / power;
		hash %= power;
		return popped;
	}
	void push(const Dir dir, const int car) {
		switch (dir) {
		case Dir::West: return push_west(car);
		case Dir::East: return push_east(car);
		default: throw 0;
		}
	}
	int pop(const Dir dir) {
		switch (dir) {
		case Dir::West: return pop_west();
		case Dir::East: return pop_east();
		default: throw 0;
		}
	}
	bool operator==(const ParkingLine& other) const {
		return hash == other.hash && power == other.power;
	}
	bool operator!=(const ParkingLine& other) const {
		return !(*this == other);
	}
};
template<>
struct std::hash<ParkingLine> {
	size_t operator()(const ParkingLine& line) const {
		size_t result{ 0 };
		const auto hasher = std::hash<long long int>();
		combine(result, hasher(line.hash));
		combine(result, hasher(line.power));
		return result;
	}
	void combine(size_t& seed, const size_t added) const {
		seed ^= added + 0x9E3779B9 + (seed << 6) + (seed >> 2);
	}
};

struct ParkingLines {
	std::vector<ParkingLine> lines;
	bool operator==(const ParkingLines& other) const {
		if (lines.size() != other.lines.size()) return false;
		for (auto i = 0; i < lines.size(); ++i) {
			if (lines[i] != other.lines[i]) return false;
		}
		return true;
	}
	const ParkingLine& operator[](const int index) const {
		return lines[index];
	}
	ParkingLine& operator[](const int index) {
		return lines[index];
	}
};
template<>
struct std::hash<ParkingLines> {
	size_t operator()(const ParkingLines& line) const {
		size_t result{ 0 };
		const auto hasher = std::hash<ParkingLine>();
		for (const auto& line : line.lines) {
			combine(result, hasher(line));
		}
		return result;
	}
	void combine(size_t& seed, const size_t added) const {
		seed ^= added + 0x9E3779B9 + (seed << 6) + (seed >> 2);
	}
};

struct Path {
	int to;
	Dir dir;
	bool operator<(const Path& other) const {
		if (to != other.to) return to < other.to;
		return dir < other.dir;
	}
	bool operator==(const Path& other) const {
		return to == other.to && dir == other.dir;
	}
};
struct Connection {
	std::vector<End> at_east, at_west;
	const std::vector<End>& next_to(const Dir dir) const {
		switch (dir) {
		case Dir::East: return at_east;
		case Dir::West: return at_west;
		default: throw 0;
		}
	}
};
Dir rev(const Dir dir) {
	switch (dir) {
	case Dir::East: return Dir::West;
	case Dir::West: return Dir::East;
	default: throw 0;
	}
}
std::vector<Path> calc_path(const ParkingLines& state, const int start, const Dir dir, const std::vector<Connection>& connections) {
	std::set<Path> set;
	std::queue<Path> queue;
	for (const auto end : connections[start].next_to(dir)) {
		queue.push(Path{ end.id, end.dir });
		set.insert(Path{ end.id, end.dir });
	}
	while (!queue.empty()) {
		const auto top = queue.front(); queue.pop();
		if (!state[top.to].is_empty()) continue;
		for (const auto end : connections[top.to].next_to(rev(top.dir))) {
			const Path path{ end.id, end.dir };
			const auto find = set.find(path);
			if (find == set.end()) {
				set.insert(path);
				queue.push(path);
			}
		}
	}
	std::vector<Path> result; result.reserve(set.size());
	std::copy(set.begin(), set.end(), std::back_inserter(result));
	return result;
}
std::vector<ParkingLines> next_states(ParkingLines state, const int start, const std::vector<Connection>& connections) {
	if (state[start].is_empty()) return {};
	std::vector<ParkingLines> result;
	for (const auto dir : all_dir) {
		for (const auto end : connections[start].next_to(dir)) {
			if (dir == end.dir && start == end.id) continue;
			int count{ 0 };
			for (auto pow = state[start].power; pow > 1; pow /= 10) ++count;
			for (auto i = 0; i < count; ++i) {
				state[end.id].push(end.dir, state[start].pop(dir));
				result.push_back(state);
			}
			for (auto i = 0; i < count; ++i) {
				state[start].push(dir, state[end.id].pop(end.dir));
			}
		}
	}
	return result;
}
std::unordered_map<ParkingLines, int> moved(ParkingLines start, const std::vector<Connection>& connections) {
	std::queue<ParkingLines> queue;
	std::unordered_map<ParkingLines, int> map;
	map[start] = 0;
	queue.push(start);
	for (auto i = 1; i <= 3; ++i) {
		for (auto c = queue.size(); c > 0; --c) {
			const auto top = queue.front(); queue.pop();
			for (auto l = 0; l < start.lines.size(); ++l) {
				for (const auto next : next_states(top, l, connections)) {
					const auto find = map.find(next);
					if (find == map.end()) {
						map[next] = i;
						queue.push(next);
					}
				}
			}
		}
	}
	return map;
}
int solve(ParkingLines start, ParkingLines goal, std::vector<Connection> connections) {
	if (start == goal) return 0;
	const auto forward = moved(start, connections);
	int min_step = INT_MAX;
	for (const auto pair : moved(goal, connections)) {
		const auto find = forward.find(pair.first);
		if (find != forward.end()) {
			min_step = std::min(min_step, pair.second + find->second);
		}
	}
	return min_step;
}
int main() {
	while (true) {
		int x, y; std::cin >> x >> y;
		if (x == 0 && y == 0) break;
		std::vector<Connection> connections(x);
		for (auto i = 0; i < y; ++i) {
			End a, b;
			std::cin >> a >> b;
			switch (a.dir) {
			case Dir::West: connections[a.id].at_west.push_back(b); break;
			case Dir::East: connections[a.id].at_east.push_back(b); break;
			default: throw 0;
			}
			switch (b.dir) {
			case Dir::West: connections[b.id].at_west.push_back(a); break;
			case Dir::East: connections[b.id].at_east.push_back(a); break;
			default: throw 0;
			}
		}
		std::vector<std::string> start(x), goal(x);
		for (auto& line : start) {
			std::cin >> line;
			if (line == "-") line = "";
		}
		for (auto& line : goal) {
			std::cin >> line;
			if (line == "-") line = "";
		}
		std::vector<char> all_char;
		for (const auto line : start) for (const auto c : line) all_char.push_back(c);
		for (const auto line : goal) for (const auto c : line) all_char.push_back(c);
		std::sort(all_char.begin(), all_char.end());
		all_char.erase(std::unique(all_char.begin(), all_char.end()), all_char.end());
		ParkingLines start_state{ std::vector<ParkingLine>(x) }, goal_state{ std::vector<ParkingLine>(x) };
		for (auto i = 0; i < x; ++i) {
			for (const auto c : start[i]) {
				start_state[i].push_east(std::distance(all_char.begin(), std::find(all_char.begin(), all_char.end(), c)));
			}
			for (const auto c : goal[i]) {
				goal_state[i].push_east(std::distance(all_char.begin(), std::find(all_char.begin(), all_char.end(), c)));
			}
		}
		std::cout << solve(start_state, goal_state, connections) << '\n';
	}
}
accuracy: 1
time_ms: 1140
memory_kb: 74076
final_rank: 8

code_snippet: #include <iostream>
#include <vector>
#include <map>
#include <unordered_map>
#include <cstdint>
#include <algorithm>
#include <iterator>
#define repeat_from(i,m,n) for (int i = (m); (i) < (n); ++(i))
#define repeat(i,n) repeat_from(i,0,n)
using namespace std;
enum we_t { W, E };
template <typename It>
void step(vector<string> const & s, map<pair<int,we_t>,vector<pair<int,we_t> > > const & g, It it) {
    int x = s.size();
    repeat (i,x) {
        repeat (n,s[i].size()+1) {
            string l = s[i].substr(0, n);
            string r = s[i].substr(n);
            for (we_t p : { W, E }) {
                if ((l.empty() and p == W) or (r.empty() and p == E)) continue;
                auto v = make_pair(i,p);
                for (auto w : g.at(v)) {
                    int  j = w.first;
                    we_t q = w.second;
                    vector<string> t = s;
                    t[i]     = p == W ? r : l;
                    string u = p == W ? l : r;
                    if (p == q) reverse(u.begin(), u.end());
                    t[j] = q == W ? u + s[j] : s[j] + u;
                    *(it ++) = t;
                }
            }
        }
    }
}
map<vector<string>,int> steps(vector<string> const & s, map<pair<int,we_t>,vector<pair<int,we_t> > > const & g, int n) {
    map<vector<string>,int> ms;
    ms[s] = 0;
    vector<vector<string> > vs;
    vs.push_back(s);
    repeat (i,n) {
        vector<vector<string> > ws;
        for (auto it : vs) {
            step(it, g, back_inserter(ws));
        }
        vs.clear();
        for (auto it : ws) {
            if (not ms.count(it)) {
                ms[it] = i+1;
                vs.push_back(it);
            }
        }
    }
    return ms;
}
int main() {
    while (true) {
        int x, y; cin >> x >> y;
        if (x == 0 and y == 0) break;
        map<pair<int,we_t>,vector<pair<int,we_t> > > g;
        repeat (i,x) for (we_t j : { W, E }) g[make_pair(i,j)];
        repeat (i,y) {
            char p, P, q, Q; cin >> p >> P >> q >> Q;
            auto a = make_pair(p - '0', P == 'W' ? W : E);
            auto b = make_pair(q - '0', Q == 'W' ? W : E);
            g[a].push_back(b);
            g[b].push_back(a);
        }
        vector<string> s(x); repeat (i,x) { cin >> s[i]; if (s[i] == "-") s[i].clear(); }
        vector<string> t(x); repeat (i,x) { cin >> t[i]; if (t[i] == "-") t[i].clear(); }
        map<vector<string>,int> s2 = steps(s, g, 2);
        map<vector<string>,int> t2 = steps(t, g, 2);
        int result = 6;
        for (auto it : s2) {
            if (t2.count(it.first)) {
                result = min(result, it.second + t2[it.first]);
            }
            if (it.second == 2) {
                vector<vector<string> > s3;
                step(it.first, g, back_inserter(s3));
                for (auto that : s3) {
                    if (t2.count(that)) {
                        result = min(result, 1 + it.second + t2[that]);
                    }
                }
            }
        }
        cout << result << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 1720
memory_kb: 4828
final_rank: 2

code_snippet: #include <iostream>
#include <cassert>
#include <vector>
#include <deque>
#include <map>
#include <unordered_map>
#include <queue>
#include <cstdint>
#include <algorithm>
#include <iterator>
#define repeat_from(i,m,n) for (int i = (m); (i) < (n); ++(i))
#define repeat(i,n) repeat_from(i,0,n)
using namespace std;
uint64_t pack(vector<string> const & s) {
    uint64_t t = 0;
    repeat (i, s.size()) {
        t *= 27;
        for (char c : s[i]) {
            t *= 27;
            t += c - 'a' + 1;
        }
    }
    return t;
}
enum we_t { W, E };
template <typename It>
void step(vector<string> const & s, map<pair<int,we_t>,vector<pair<int,we_t> > > const & g, It it) {
    int x = s.size();
    repeat (i,x) {
        repeat (n,s[i].size()+1) {
            string l = s[i].substr(0, n);
            string r = s[i].substr(n);
            for (we_t p : { W, E }) {
                if ((l.empty() and p == W) or (r.empty() and p == E)) continue;
                auto v = make_pair(i,p);
                for (auto w : g.at(v)) {
                    int  j = w.first;
                    we_t q = w.second;
                    vector<string> t = s;
                    t[i]     = p == W ? r : l;
                    string u = p == W ? l : r;
                    if (p == q) reverse(u.begin(), u.end());
                    t[j] = q == W ? u + s[j] : s[j] + u;
                    *(it ++) = t;
                }
            }
        }
    }
}
map<vector<string>,int> steps(vector<string> const & s, map<pair<int,we_t>,vector<pair<int,we_t> > > const & g, int n) {
    map<vector<string>,int> ms;
    ms[s] = 0;
    vector<vector<string> > vs;
    vs.push_back(s);
    repeat (i,n) {
        vector<vector<string> > ws;
        for (auto it : vs) {
            step(it, g, back_inserter(ws));
        }
        vs.clear();
        for (auto it : ws) {
            if (not ms.count(it)) {
                ms[it] = i+1;
                vs.push_back(it);
            }
        }
    }
    return ms;
}
int main() {
    while (true) {
        int x, y; cin >> x >> y;
        if (x == 0 and y == 0) break;
        map<pair<int,we_t>,vector<pair<int,we_t> > > g;
        repeat (i,x) for (we_t j : { W, E }) g[make_pair(i,j)];
        repeat (i,y) {
            char p, P, q, Q; cin >> p >> P >> q >> Q;
            auto a = make_pair(p - '0', P == 'W' ? W : E);
            auto b = make_pair(q - '0', Q == 'W' ? W : E);
            g[a].push_back(b);
            g[b].push_back(a);
        }
        vector<string> s(x); repeat (i,x) { cin >> s[i]; if (s[i] == "-") s[i].clear(); }
        vector<string> t(x); repeat (i,x) { cin >> t[i]; if (t[i] == "-") t[i].clear(); }
        map<vector<string>,int> s2 = steps(s, g, 2);
        map<vector<string>,int> t2 = steps(t, g, 2);
        unordered_map<uint64_t,int> t2h; // required
        for (auto it : t2) t2h[pack(it.first)] = it.second;
        int result = 6;
        for (auto it : s2) {
            uint64_t ha = pack(it.first);
            if (t2h.count(ha)) {
                result = min(result, it.second + t2h[ha]);
            }
            if (it.second == 2) {
                vector<vector<string> > s3;
                step(it.first, g, back_inserter(s3));
                for (auto that : s3) {
                    uint64_t hb = pack(that);
                    if (t2h.count(hb)) {
                        result = min(result, 1 + it.second + t2h[hb]);
                    }
                }
            }
        }
        cout << result << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 1090
memory_kb: 4828
final_rank: 1

code_snippet: #include <iostream>
#include <vector>
#include <deque>
#include <map>
#include <unordered_map>
#include <queue>
#include <cstdint>
#include <algorithm>
#include <iterator>
#define repeat_from(i,m,n) for (int i = (m); (i) < (n); ++(i))
#define repeat(i,n) repeat_from(i,0,n)
using namespace std;
uint64_t pack(vector<deque<char> > const & s) {
    uint64_t t = 0;
    repeat (i, s.size()) {
        t *= 27;
        for (char c : s[i]) {
            t *= 27;
            t += c - 'a' + 1;
        }
    }
    return t;
}
enum we_t { W, E };
template <typename It>
void step(vector<deque<char> > const & s, map<pair<int,we_t>,vector<pair<int,we_t> > > const & g, It it) {
    int x = s.size();
    repeat (i,x) {
        repeat_from (n,1,s[i].size()+1) {
            for (we_t p : { W, E }) {
                auto v = make_pair(i,p);
                for (auto w : g.at(v)) {
                    int j = w.first;
                    vector<deque<char> > t = s;
                    queue<char> u;
                    repeat (k,n) {
                        if (v.second == W) {
                            u.push(t[i].front());
                            t[i].pop_front();
                        } else {
                            u.push(t[i].back());
                            t[i].pop_back();
                        }
                    }
                    repeat (k,n) {
                        if (w.second == W) {
                            t[j].push_front(u.front());
                        } else {
                            t[j].push_back(u.front());
                        }
                        u.pop();
                    }
                    *(it ++) = t;
                }
            }
        }
    }
}
map<vector<deque<char> >,int> steps(vector<deque<char> > const & s, map<pair<int,we_t>,vector<pair<int,we_t> > > const & g, int n) {
    map<vector<deque<char> >,int> ms;
    ms[s] = 0;
    vector<vector<deque<char> > > vs;
    vs.push_back(s);
    repeat (i,n) {
        vector<vector<deque<char> > > ws;
        for (auto it : vs) {
            step(it, g, back_inserter(ws));
        }
        vs.clear();
        for (auto it : ws) {
            if (not ms.count(it)) {
                ms[it] = i+1;
                vs.push_back(it);
            }
        }
    }
    return ms;
}
int main() {
    while (true) {
        int x, y; cin >> x >> y;
        if (x == 0 and y == 0) break;
        map<pair<int,we_t>,vector<pair<int,we_t> > > g;
        repeat (i,x) for (we_t j : { W, E }) g[make_pair(i,j)];
        repeat (i,y) {
            char p, P, q, Q; cin >> p >> P >> q >> Q;
            auto a = make_pair(p - '0', P == 'W' ? W : E);
            auto b = make_pair(q - '0', Q == 'W' ? W : E);
            g[a].push_back(b);
            g[b].push_back(a);
        }
        vector<deque<char> > s(x); repeat (i,x) { string a; cin >> a; if (a == "-") a.clear(); s[i] = deque<char>(a.begin(), a.end()); }
        vector<deque<char> > t(x); repeat (i,x) { string a; cin >> a; if (a == "-") a.clear(); t[i] = deque<char>(a.begin(), a.end()); }
        map<vector<deque<char> >,int> s2 = steps(s, g, 2);
        map<vector<deque<char> >,int> t2 = steps(t, g, 2);
        unordered_map<uint64_t,int> t2h;
        for (auto it : t2) t2h[pack(it.first)] = it.second;
        int result = 6;
        for (auto it : s2) {
            uint64_t ha = pack(it.first);
            if (t2h.count(ha)) {
                result = min(result, it.second + t2h[ha]);
            }
            if (it.second == 2) {
                vector<vector<deque<char> > > s3;
                step(it.first, g, back_inserter(s3));
                for (auto that : s3) {
                    uint64_t hb = pack(that);
                    if (t2h.count(hb)) {
                        result = min(result, 1 + it.second + t2h[hb]);
                    }
                }
            }
        }
        cout << result << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 4430
memory_kb: 86408
final_rank: 13

code_snippet: #include <algorithm>
#include <array>
#include <cstdlib>
#include <iostream>
#include <queue>
#include <unordered_map>
#include <vector>
using namespace std;

template<class T> inline void chmin(T &a, const T &b) { if(a > b) a = b; }

typedef array<int, 2> A;
typedef pair<A, A> E;
typedef unsigned hash_t;

hash_t rolling_hash(const string &s) {
	static constexpr hash_t base = 1000000007;
	hash_t res = 0;
	for(const auto &c : s) {
		res = res * base + c;
	}
	return res;
}
 
string to_str(const vector<string> &state) {
	string res = "";
	for(const auto &s : state) {
		res += s + ":";
	}
	return res;
}
 
unordered_map<hash_t, int> bfs(int limit, const vector<string> &start, const vector<E> &exchanges) {
	unordered_map<hash_t, int> res;
	queue<vector<string>> que;
 
	res.insert({rolling_hash(to_str(start)), 0});
	que.push(start);
 
	while(!que.empty()) {
		vector<string> state = que.front();
		que.pop();
		const int d = res.at(rolling_hash(to_str(state)));
 
		if(d == limit) break;
 
		for(const auto &element : exchanges) {
			const A &pos = element.first;
			const A &dir = element.second;
			const array<string, 2> train{move(state[pos.front()]), move(state[pos.back()])};

			for(int i = 0; i <= 1; ++i) {
				const int from = i;
				const int to = 1 - i;

				const int &p1 = pos[from];
				const int &p2 = pos[to];
				const int &d1 = dir[from];
				const int &d2 = dir[to];
				const string &t1 = train[from];
				const string &t2 = train[to];

				for(int num = 1; num <= t1.size(); ++num) {
					string tmp = (d1 ? t1.substr(0, num) : t1.substr(t1.size() - num));
					if(d1 == d2) reverse(tmp.begin(), tmp.end());
					state[p1] = (d1 ? t1.substr(num) : t1.substr(0, t1.size() - num));
					state[p2] = (d2 ? tmp + t2 : t2 + tmp);
 
					const hash_t h = rolling_hash(to_str(state));
					if(!res.count(h)) {
						res.insert({h, d + 1});
						que.push(state);
					}
				}
			}
 
			state[pos.front()] = move(train.front());
			state[pos.back()] = move(train.back());
		}
	}
 
	return res;
}
 
int main(){
	cin.tie(nullptr);
	ios::sync_with_stdio(false);
 
	for(int x, y; cin >> x >> y && x;) {
		vector<E> exchanges;
		exchanges.reserve(y);
 
		for(int i = 0; i < y; ++i) {
			string a, b;
			cin >> a >> b;
 
			const int p1 = a[0] - '0';
			const int d1 = (a[1] == 'W');
			const int p2 = b[0] - '0';
			const int d2 = (b[1] == 'W');
 
			exchanges.emplace_back(A{p1, p2}, A{d1, d2});
		}
 
		vector<string> lines(x), goal(x);
 
		for(auto &e : lines) {
			cin >> e;
			if(e == "-") e = "";
		}
 
		for(auto &e : goal) {
			cin >> e;
			if(e == "-") e = "";
		}
     
		const auto d1 = bfs(3, lines, exchanges);
		const auto d2 = bfs(2, goal, exchanges);
 
		int ans = 6;
		for(const auto &e1 : d2) {
			if(ans <= e1.second) continue;
 
			if(d1.count(e1.first)) {
				chmin(ans, e1.second + d1.at(e1.first));
			}
		}
 
		cout << ans << endl;
	}
 
	return EXIT_SUCCESS;
}
accuracy: 1
time_ms: 2010
memory_kb: 31476
final_rank: 5

code_snippet: #include <bits/stdc++.h>
using namespace std;

#define dump(a) (cerr << #a << " = " << (a) << endl)

#define REP(i,a,b) for(int i=(a);i < (int)(b); i++)
#define rep(i,n) REP(i,0,n)
#define ALL(v) begin(v), end(v)

int x, y;
vector<pair<pair<int, bool>, pair<int, bool>>> exchanges;

typedef unsigned long long hash_t;
hash_t rolling_hash(const string &s) {
  constexpr hash_t base = 1000000007;
  hash_t res = 0;
  for(const auto &c : s) {
    res = res * base + c;
  }
  return res;
}

string to_str(const vector<string> &state) {
  string res = "";
  for(const auto &s : state) {
    res += s + ":";
  }
  return res;
}

unordered_map<hash_t, int> bfs(int limit, const vector<string> &start) {
  unordered_map<hash_t, int> res;
  queue<vector<string>> que;

  res.insert({rolling_hash(to_str(start)), 0});
  que.push(start);

  while(!que.empty()) {
    vector<string> state = que.front();
    que.pop();
    const int d = res[rolling_hash(to_str(state))];

    if(d == limit) break;

    for(const auto &element : exchanges) {
      const int p1 = element.first.first;
      const bool d1 = element.first.second;
      const int p2 = element.second.first;
      const bool d2 = element.second.second;

      const string t1 = move(state[p1]);
      const string t2 = move(state[p2]);

      // p1 -> p2
      for(int num = 1; num <= t1.size(); ++num) {
	string tmp = (d1 ? t1.substr(0, num) : t1.substr(t1.size() - num));
	if(d1 == d2) reverse(tmp.begin(), tmp.end());
	state[p1] = (d1 ? t1.substr(num) : t1.substr(0, t1.size() - num));
	state[p2] = (d2 ? tmp + t2 : t2 + tmp);

	const hash_t h = rolling_hash(to_str(state));
	if(!res.count(h)) {
	  res.insert({h, d + 1});
	  que.push(state);
	}
      }

      // p2 -> p1
      for(int num = 1; num <= t2.size(); ++num) {
	string tmp = (d2 ? t2.substr(0, num) : t2.substr(t2.size() - num));
	if(d1 == d2) reverse(tmp.begin(), tmp.end());
	state[p1] = (d1 ? tmp + t1 : t1 + tmp);
	state[p2] = (d2 ? t2.substr(num) : t2.substr(0, t2.size() - num));

	const hash_t h = rolling_hash(to_str(state));
	if(!res.count(h)) {
	  res.insert({h, d + 1});
	  que.push(state);
	}
      }

      state[p1] = move(t1);
      state[p2] = move(t2);
    }
  }

  return res;
}

int main(){
  cin.tie(nullptr);
  ios::sync_with_stdio(false);

  while(cin >> x >> y && x) {
    exchanges.clear();
    exchanges.reserve(y);

    for(int i = 0; i < y; ++i) {
      string a, b;
      cin >> a >> b;

      const int p1 = a[0] - '0';
      const bool d1 = (a[1] == 'W');
      const int p2 = b[0] - '0';
      const bool d2 = (b[1] == 'W');

      exchanges.emplace_back(make_pair(p1, d1), make_pair(p2, d2));
    }

    vector<string> lines(x), goal(x);

    for(auto &e : lines) {
      cin >> e;
      if(e == "-") e = "";
    }

    for(auto &e : goal) {
      cin >> e;
      if(e == "-") e = "";
    }
    
    const auto d1 = bfs(3, lines);
    const auto d2 = bfs(2, goal);

    vector<string> tmp{"cc", "", "bbaadee"};

    int ans = 6;
    for(const auto &e1 : d2) {
      if(ans <= e1.second) continue;

      if(d1.count(e1.first)) {
	ans = min(ans, e1.second + d1.at(e1.first));
      }
    }

    cout << ans << endl;
  }

  return 0;
}
accuracy: 1
time_ms: 2060
memory_kb: 31216
final_rank: 6

code_snippet: #include <iostream>
#include <vector>
#include <set>
#include <map>
#include <algorithm>
#include <queue>
#include <cstring>
#include <climits>
using namespace std;

typedef pair<int,int> P;
typedef pair<vector<string>, int> VI;

int n;
vector<P> t[4][2];
vector<string> start, end;
map<vector<string>, int> half;

int ans;

void enumerateHalf(){
  queue<VI> open;
  open.push(VI(start, 0));
  half[start] = 0;

  while(!open.empty()){
    VI vi = open.front();
    open.pop();
    vector<string> vec = vi.first;
    int step = vi.second;

    for(int from = 0; from < n; from++){
      if(vec[from].size() == 0) continue;

      for(int cut = 0; cut < vec[from].size(); cut++){
        string cut_str[2] = {
          vec[from].substr(0, cut),
          vec[from].substr(cut)
        };
        string rev_str[2] = {cut_str[0], cut_str[1]};
        reverse(rev_str[0].begin(), rev_str[0].end());
        reverse(rev_str[1].begin(), rev_str[1].end());

        for(int from_dir = 0; from_dir < 2; from_dir++){
          if(cut_str[from_dir].size() == 0) continue;

          for(int to_idx = 0; to_idx < t[from][from_dir].size(); to_idx++){
            int to = t[from][from_dir][to_idx].first;
            int to_dir = t[from][from_dir][to_idx].second;
            vector<string> nvec = vec;

            if     (from_dir == 0 && to_dir == 0) nvec[to] = rev_str[from_dir] + nvec[to];
            else if(from_dir == 0 && to_dir == 1) nvec[to] += cut_str[from_dir];
            else if(from_dir == 1 && to_dir == 0) nvec[to] = cut_str[from_dir] + nvec[to];
            else                                  nvec[to] += rev_str[from_dir];

            nvec[from] = cut_str[!from_dir];

            map<vector<string>,int>::iterator tmp_iter = half.find(nvec);

            if(tmp_iter != half.end()) continue;
            half[nvec] = step + 1;

            if(step == 2) continue;
            open.push(VI(nvec, step + 1));
          }
        }
      }
    }
  }
}

void bfs(){
  queue<VI> open;
  open.push(VI(end, 0));

  map<vector<string>,int>::iterator tmp_iter = half.find(end);
  if(tmp_iter != half.end()) ans = min(ans, tmp_iter->second);

  while(!open.empty()){
    VI vi = open.front();
    open.pop();
    vector<string> vec = vi.first;
    int step = vi.second;

    for(int from = 0; from < n; from++){
      if(vec[from].size() == 0) continue;

      for(int cut = 0; cut < vec[from].size(); cut++){
        string cut_str[2] = {
          vec[from].substr(0, cut),
          vec[from].substr(cut)
        };
        string rev_str[2] = {cut_str[0], cut_str[1]};
        reverse(rev_str[0].begin(), rev_str[0].end());
        reverse(rev_str[1].begin(), rev_str[1].end());

        for(int from_dir = 0; from_dir < 2; from_dir++){
          if(cut_str[from_dir].size() == 0) continue;

          for(int to_idx = 0; to_idx < t[from][from_dir].size(); to_idx++){
            int to = t[from][from_dir][to_idx].first;
            int to_dir = t[from][from_dir][to_idx].second;
            vector<string> nvec = vec;

            if     (from_dir == 0 && to_dir == 0) nvec[to] = rev_str[from_dir] + nvec[to];
            else if(from_dir == 0 && to_dir == 1) nvec[to] += cut_str[from_dir];
            else if(from_dir == 1 && to_dir == 0) nvec[to] = cut_str[from_dir] + nvec[to];
            else                                  nvec[to] += rev_str[from_dir];

            nvec[from] = cut_str[!from_dir];

            map<vector<string>,int>::iterator tmp_iter = half.find(nvec);

            if(tmp_iter != half.end()){
              ans = min(ans, step + 1 + tmp_iter->second);
              continue;
            }

            if(step == 2) continue;
            open.push(VI(nvec, step + 1));
          }
        }
      }
    }
  }
}

void solve(){
  half.clear();
  enumerateHalf();

  ans = INT_MAX;
  bfs();
  cout << ans << endl;
}

int main(){
  int m;

  while(cin >> n >> m, n || m){
    for(int i = 0; i < 4; i++){
      for(int j = 0; j < 2; j++){
        t[i][j].clear();
      }
    }

    for(int i = 0; i < m; i++){
      string from, to;
      cin >> from >> to;

      int from_line = from[0] - '0';
      int from_dir = (from[1] == 'W' ? 0 : 1);
      int to_line = to[0] - '0';
      int to_dir = (to[1] == 'W' ? 0 : 1);

      t[from_line][from_dir].push_back(P(to_line, to_dir));
      t[to_line][to_dir].push_back(P(from_line, from_dir));
    }

    start.clear();
    end.clear();

    for(int i = 0; i < n; i++){
      string s;
      cin >> s;
      if(s == "-") s = "";
      start.push_back(s);
    }

    for(int i = 0; i < n; i++){
      string s;
      cin >> s;
      if(s == "-") s = "";
      end.push_back(s);
    }

    solve();
  }
}
accuracy: 1
time_ms: 6010
memory_kb: 25732
final_rank: 11

code_snippet: #include <iostream>
#include <vector>
#include <set>
#include <map>
#include <algorithm>
#include <queue>
#include <cstring>
#include <climits>
using namespace std;

typedef pair<int,int> P;
typedef pair<vector<string>, int> VI;

int n;
vector<P> t[4][2];
vector<string> start, end;
map<vector<string>, int> half;

int ans;

void enumerateHalf(){
  queue<VI> open;
  open.push(VI(start, 0));
  half[start] = 0;

  while(!open.empty()){
    VI vi = open.front();
    open.pop();
    vector<string> vec = vi.first;
    int step = vi.second;

    for(int from = 0; from < n; from++){
      if(vec[from].size() == 0) continue;

      for(int cut = 0; cut < vec[from].size(); cut++){
        string cut_str[2] = {
          vec[from].substr(0, cut),
          vec[from].substr(cut)
        };
        string rev_str[2] = {cut_str[0], cut_str[1]};
        reverse(rev_str[0].begin(), rev_str[0].end());
        reverse(rev_str[1].begin(), rev_str[1].end());

        for(int from_dir = 0; from_dir < 2; from_dir++){
          if(cut_str[from_dir].size() == 0) continue;

          for(int to_idx = 0; to_idx < t[from][from_dir].size(); to_idx++){
            int to = t[from][from_dir][to_idx].first;
            int to_dir = t[from][from_dir][to_idx].second;
            vector<string> nvec = vec;

            if     (from_dir == 0 && to_dir == 0) nvec[to] = rev_str[from_dir] + nvec[to];
            else if(from_dir == 0 && to_dir == 1) nvec[to] += cut_str[from_dir];
            else if(from_dir == 1 && to_dir == 0) nvec[to] = cut_str[from_dir] + nvec[to];
            else                                  nvec[to] += rev_str[from_dir];

            nvec[from] = cut_str[!from_dir];

            map<vector<string>,int>::iterator tmp_iter = half.find(nvec);

            if(tmp_iter != half.end()) continue;
            half[nvec] = step + 1;

            if(step == 2) continue;
            open.push(VI(nvec, step + 1));
          }
        }
      }
    }
  }
}

void rec(int step, vector<string> vec){
  map<vector<string>,int>::iterator tmp_iter = half.find(vec);
  if(tmp_iter != half.end()){
    ans = min(ans, step + tmp_iter->second);
    return;
  }
  if(step == 3) return;

  for(int from = 0; from < n; from++){
    if(vec[from].size() == 0) continue;

    for(int cut = 0; cut < vec[from].size(); cut++){
      string cut_str[2] = {
        vec[from].substr(0, cut),
        vec[from].substr(cut)
      };
      string rev_str[2] = {cut_str[0], cut_str[1]};
      reverse(rev_str[0].begin(), rev_str[0].end());
      reverse(rev_str[1].begin(), rev_str[1].end());

      for(int from_dir = 0; from_dir < 2; from_dir++){
        if(cut_str[from_dir].size() == 0) continue;

        for(int to_idx = 0; to_idx < t[from][from_dir].size(); to_idx++){
          int to = t[from][from_dir][to_idx].first;
          int to_dir = t[from][from_dir][to_idx].second;
          vector<string> nvec = vec;

          if     (from_dir == 0 && to_dir == 0) nvec[to] = rev_str[from_dir] + nvec[to];
          else if(from_dir == 0 && to_dir == 1) nvec[to] += cut_str[from_dir];
          else if(from_dir == 1 && to_dir == 0) nvec[to] = cut_str[from_dir] + nvec[to];
          else                                  nvec[to] += rev_str[from_dir];

          nvec[from] = cut_str[!from_dir];

          rec(step + 1, nvec);
        }
      }
    }
  }
}

void solve(){
  half.clear();
  enumerateHalf();

  ans = INT_MAX;
  rec(0, end);
  cout << ans << endl;
}

int main(){
  int m;

  while(cin >> n >> m, n || m){
    for(int i = 0; i < 4; i++){
      for(int j = 0; j < 2; j++){
        t[i][j].clear();
      }
    }

    for(int i = 0; i < m; i++){
      string from, to;
      cin >> from >> to;

      int from_line = from[0] - '0';
      int from_dir = (from[1] == 'W' ? 0 : 1);
      int to_line = to[0] - '0';
      int to_dir = (to[1] == 'W' ? 0 : 1);

      t[from_line][from_dir].push_back(P(to_line, to_dir));
      t[to_line][to_dir].push_back(P(from_line, from_dir));
    }

    start.clear();
    end.clear();

    for(int i = 0; i < n; i++){
      string s;
      cin >> s;
      if(s == "-") s = "";
      start.push_back(s);
    }

    for(int i = 0; i < n; i++){
      string s;
      cin >> s;
      if(s == "-") s = "";
      end.push_back(s);
    }

    solve();
  }
}
accuracy: 1
time_ms: 6370
memory_kb: 24420
final_rank: 12

code_snippet: #include <iostream>
#include <map>
#include <string>
#include <vector>
#include <algorithm>
#include <queue>
 
using namespace std;
 
typedef pair<vector<string>, int> P;
 
bool G[4][2][4][2];
map<vector<string>, int> dat, dat2;
int n, m;
 
void init(){
  fill(G[0][0][0], G[4][0][0], false);
  dat.clear();
  dat2.clear();
}
 
void bfs1(vector<string> &s){
  queue<P> que;
  dat[s] = 0;
  que.push(P(s, 0));
  while(!que.empty()){
    vector<string> u = que.front().first;
    int dist = que.front().second;
    que.pop();
    for(int i=0;i<n;i++){
      for(int j=-1;j<(int)u[i].size();j++){
        int p1 = i;
        for(int d1=0;d1<2;d1++){
          for(int p2=0;p2<n;p2++){
            for(int d2=0;d2<2;d2++){
              if(G[p1][d1][p2][d2]){
                vector<string> v;
                v.resize(n);
                string next;
                for(int k=0;k<n;k++){
                  if(k == p1){
                    if(d1 == 0){
                      next = u[k].substr(j+1);
                      v[k] = next;
                    }else{
                      next = u[k].substr(0, j+1);
                      v[k] = next;
                    }
                  }else{
                    v[k] = u[k];
                  }
                }
                if(d1 == 0){
                  if(d2 == 0){
                    next = u[p1].substr(0, j+1);
                    reverse(next.begin(), next.end());                  
                    v[p2] = next + v[p2];
                  }else{
                    next = u[p1].substr(0, j+1);
                    v[p2] = v[p2] + next;
                  }
                }else{
                  if(d2 == 0){
                    next = u[p1].substr(j+1);
                    v[p2] = next + v[p2];
                  }else{
                    next = u[p1].substr(j+1);
                    reverse(next.begin(), next.end());                  
                    v[p2] = v[p2] + next;
                  }
                }
                if(dat.find(v) == dat.end()){
                  dat[v] = dist + 1;
                  if(dist + 1 < 2) que.push(P(v, dist + 1));
                }
              }
            }
          }
        }
      }
    }
  }
}
 
int bfs2(vector<string> &s){
  queue<P> que;
  dat2[s] = 0;
  que.push(P(s, 0));
  if(dat.find(s) != dat.end()) return dat[s];
  int res = 6;
  while(!que.empty()){
    vector<string> u = que.front().first;
    int dist = que.front().second;
    que.pop();
    if(dist >= 3) continue;
    for(int i=0;i<n;i++){
      for(int j=-1;j<(int)u[i].size();j++){
        int p1 = i;
        for(int d1=0;d1<2;d1++){
          for(int p2=0;p2<n;p2++){
            for(int d2=0;d2<2;d2++){
              if(G[p1][d1][p2][d2]){
                vector<string> v;
                v.resize(n);
                string next;
                for(int k=0;k<n;k++){
                  if(k == p1){
                    if(d1 == 0){
                      next = u[k].substr(j+1);
                      v[k] = next;
                    }else{
                      next = u[k].substr(0, j+1);
                      v[k] = next;
                    }
                  }else{
                    v[k] = u[k];
                  }
                }
                if(d1 == 0){
                  if(d2 == 0){
                    next = u[p1].substr(0, j+1);
                    reverse(next.begin(), next.end());                  
                    v[p2] = next + v[p2];
                  }else{
                    next = u[p1].substr(0, j+1);
                    v[p2] = v[p2] + next;
                  }
                }else{
                  if(d2 == 0){
                    next = u[p1].substr(j+1);
                    v[p2] = next + v[p2];
                  }else{
                    next = u[p1].substr(j+1);
                    reverse(next.begin(), next.end());                  
                    v[p2] = v[p2] + next;
                  }
                }
                if(dat2.find(v) == dat2.end()){
                  if(dat.find(v) != dat.end()){
                    res = min(res, dist + 1 + dat[v]);
                    continue;
                  }
                  dat2[v] = dist + 1;
                  if(dist + 1 < 3) que.push(P(v, dist + 1));
                }
              }
            }
          }
        }
      }
    }
  }
  return res;
}
 
vector<string> cre(){
  vector<string> vec;
  for(int i=0;i<n;i++){
    string in;
    cin >> in;
    if(in == "-") in = "";
    vec.push_back(in);
  }
  return vec;
}
 
main(){
  while(cin >> n >> m && (n|m)){
    init();
    for(int i=0;i<m;i++){
      string a, b;
      cin >> a >> b;
      int p1 = a[0] - '0';
      int d1 = (a[1] == 'W' ? 0 : 1);
      int p2 = b[0] - '0';
      int d2 = (b[1] == 'W' ? 0 : 1);
      G[p1][d1][p2][d2] = true;
      G[p2][d2][p1][d1] = true;
    }
    vector<string> s = cre();
    bfs1(s);
    vector<string> t = cre();
    cout << bfs2(t) << endl;
  }
}
accuracy: 1
time_ms: 4270
memory_kb: 41076
final_rank: 10

code_snippet: #include<iostream>
#include<string>
#include<queue>
#include<map>
#define MAX 4
#define LIMIT 6
#define FORWARD 0
#define BACK 1
#define WEST 0
#define EAST 1
#define BUFFER 40

using namespace std;

class Load{
 public:
  char buffer[BUFFER];
  int head, tail, size;
  Load(){}
  Load( string str ){
    head = tail = BUFFER/2;
    size = 0;
    for ( int i = 0; i < str.size(); i++ ){
      buffer[tail++] = str[i];
      size++;
    }
  }
  
  void intoW( char ch ){ buffer[--head] = ch; size++; }
  void intoE( char ch ){ buffer[tail++] = ch; size++; }
  char fromW(){ char ch = buffer[head]; head++; size--; return ch; }
  char fromE(){ char ch = buffer[tail-1]; tail--; size--; return ch; }
  
  bool operator < ( const Load &l ) const {
    if ( size != l.size ) return size < l.size;
    for ( int i = head, j = l.head; i < tail; i++, j++ ){
      if ( buffer[i] == l.buffer[j] ) continue;
      return buffer[i] < l.buffer[j];
    }
    return false;
  }
  
  bool operator == ( const Load &l ) const {
    if ( size != l.size ) return false;
    for ( int i = head, j = l.head; i < tail; i++, j++ ){
      if ( buffer[i] != l.buffer[j] ) return false;
    }
    return true;
  }
  
  bool operator != ( const Load &l ) const {
    if ( size != l.size ) return true;
    for ( int i = head, j = l.head; i < tail; i++, j++ ){
      if ( buffer[i] != l.buffer[j] ) return true;
    }
    return false;
  }
};

class Station{
 public:
  int nload;
  Load loads[MAX];
  int id;
  
  Station(){}
  Station( int nload): nload(nload){}
  
  bool operator < ( const Station &s ) const {
    for ( int i = 0; i < nload; i++ ){
      if ( loads[i] == s.loads[i] ) continue;
      return loads[i] < s.loads[i];
    }
    return false;
  }
  
  bool operator == ( const Station &s ) const {
    for ( int i = 0; i < nload; i++ ){
      if ( loads[i] != s.loads[i] ) return false;
    }
    return true;
  }
};


Station initial, goal;
int nload;
bool M[MAX][2][MAX][2]; 

map<Station, int> BS; 
map<Station, int> FS; 

Station getNext(Station v, int d, int s, int sd, int t, int td){
  int nd;
  
  if ( sd == WEST ){
    if ( td == WEST ){
      for ( int i = 0; i < d; i++  ){
	v.loads[t].intoW(v.loads[s].fromW());
      }
    } else {
      for ( int i = 0; i < d; i++  ){
	v.loads[t].intoE(v.loads[s].fromW());
      }
    }
  } else {
    if ( td == WEST ){
      nd = v.loads[s].size - d;
      for ( int i = 0; i < nd; i++ ){
	v.loads[t].intoW(v.loads[s].fromE());
      }
    } else {
      nd = v.loads[s].size - d;
      for ( int i = 0; i < nd; i++ ){
	v.loads[t].intoE(v.loads[s].fromE());
      }
    }
  }
  
  return v;
}

int bfs( Station source, map<Station, int> &D, int mode ){
  queue<Station> Q;
  Q.push(source);
  D[source] = 0;
  
  Station u, v;
  
  if ( mode == FORWARD && BS.find(source) != BS.end() ) return BS[source];
  
  while(!Q.empty()){
    u = Q.front(); Q.pop();
    int dist = D[u];
    
    if ( mode == BACK && dist >= 3 ) return 0;
    
    for ( int s = 0; s < nload; s++ ){
      for ( int d = 0; d < u.loads[s].size; d++ ){
	for ( int t = 0; t < nload; t++ ){
	  for ( int sd = 0; sd < 2; sd++ ){
	    for ( int td = 0; td < 2; td++ ){
	      if ( M[s][sd][t][td] ){
		v = getNext(u, d, s, sd, t, td );
		if ( D.find(v) == D.end() ){
		  D[v] = dist + 1;
		  if ( mode == FORWARD ){
		    if ( BS.find(v) != BS.end() ) {
		      return BS[v] + dist + 1;
		    }
		  } 
		  Q.push(v);
		}
	      }
	    }
	  }
	}
      }
    }
  }
  return -1;
}

void compute(){
  BS = map<Station, int>();
  FS = map<Station, int>();
  bfs(goal, BS, BACK);
  cout << bfs(initial, FS, FORWARD) << endl;
}

bool input(){
  int y;
  cin >> nload >> y;
  if ( nload == 0 && y == 0 ) return false;
  
  for ( int i = 0; i < nload; i++ ){
    for ( int j = 0; j < nload; j++ ){
      M[i][WEST][j][WEST] = false;
      M[i][WEST][j][EAST] = false;
      M[i][EAST][j][WEST] = false;
      M[i][EAST][j][EAST] = false;
    }
  }
  int sl, tl; 
  char sd, td; 
  for ( int i = 0; i < y; i++ ){
    cin >> sl >> sd >> tl >> td;
    M[sl][(sd == 'W' ? WEST : EAST)][tl][(td == 'W' ? WEST : EAST)] = true;
    M[tl][(td == 'W' ? WEST : EAST)][sl][(sd == 'W' ? WEST : EAST)] = true;
  }
  
  initial = Station(nload);
  goal = Station(nload);
  
  string train;
  for ( int i = 0; i < nload; i++ ) {
    cin >> train; if ( train == "-" ) train = "";
    initial.loads[i] = Load(train);
  }
  for ( int i = 0; i < nload; i++ ) {
    cin >> train; if ( train == "-" ) train = "";
    goal.loads[i] = Load(train);
  }
  
  return true;
}

main(){
  while( input() ) compute();
}
accuracy: 1
time_ms: 1610
memory_kb: 75556
final_rank: 9

code_snippet: #include <cstdio>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <bitset>
#include <numeric>
#include <climits>
#include <cfloat>
using namespace std;

int n;
vector<vector<int> > to;

void solve(vector<string> start, map<vector<string>, int>& history)
{
    queue<vector<string> > q1;
    q1.push(start);
    history[start] = 0;

    for(int a=1; a<=3; ++a){
        queue<vector<string> > q2;
        while(!q1.empty()){
            vector<string> s = q1.front();
            q1.pop();

            for(int i=0; i<n*2; ++i){
                for(unsigned j=0; j<to[i].size(); ++j){
                    vector<string> t = s;
                    while(!t[i/2].empty()){
                        char c;
                        if(i % 2 == 0){
                            c = t[i/2][0];
                            t[i/2] = t[i/2].substr(1);
                        }else{
                            c = t[i/2][t[i/2].size()-1];
                            t[i/2] = t[i/2].substr(0, t[i/2].size()-1);
                        }

                        if(to[i][j] % 2 == 0){
                            t[to[i][j]/2] = c + t[to[i][j]/2];
                        }else{
                            t[to[i][j]/2] += c;
                        }

                        if(history.find(t) == history.end()){
                            q2.push(t);
                            history[t] = a;
                        }
                    }
                }
            }
        }
        q1 = q2;
    }
}

int main()
{
    for(;;){
        int m;
        cin >> n >> m;
        if(n == 0)
            return 0;

        to.assign(2*n, vector<int>());
        for(int i=0; i<m; ++i){
            string s, t;
            cin >> s >> t;
            int a = (s[0] - '0') * 2;
            int b = (t[0] - '0') * 2;
            if(s[1] == 'E')
                ++ a;
            if(t[1] == 'E')
                ++ b;
            to[a].push_back(b);
            to[b].push_back(a);
        }

        vector<string> s(n), t(n);
        for(int i=0; i<n; ++i){
            cin >> s[i];
            if(s[i] == "-")
                s[i] = "";
        }
        for(int i=0; i<n; ++i){
            cin >> t[i];
            if(t[i] == "-")
                t[i] = "";
        }

        map<vector<string>, int> history1, history2;
        solve(t, history2);
        solve(s, history1);

        int ret = INT_MAX;
        map<vector<string>, int>::iterator it1, it2;
        it1 = history1.begin();
        it2 = history2.begin();
        while(it1 != history1.end() && it2 != history2.end()){
            if(it1->first == it2->first)
                ret = min(ret, it1->second + it2->second);
            if(it1->first < it2->first)
                ++ it1;
            else
                ++ it2;
        }

        cout << ret << endl;
    }
}
accuracy: 1
time_ms: 7430
memory_kb: 91652
final_rank: 15

code_snippet: #include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>

using namespace std;

template <class Key, class Value>
struct HashMap {

    static const int MAXH = 999983;
    struct Edge {
        Key to;
        Value v;
        Edge *next;
    } *head[MAXH];

    void set(const Key &key, const Value &value) {

        int hv = (unsigned int)key.hash_value() % MAXH;
        Edge *p = new Edge;
        p -> to = key;
        p -> v = value;
        p -> next = head[hv];
        head[hv] = p;
    }

    const Value &get(const Key &key) {

        int hv = (unsigned int)key.hash_value() % MAXH;
        for (Edge *p = head[hv]; p; p = p -> next)
            if (p -> to == key) return p -> v;
    }

    bool exist(const Key &key) {

        int hv = (unsigned int)key.hash_value() % MAXH;
        for (Edge *p = head[hv]; p; p = p -> next)
            if (p -> to == key) return true;
        return false;
    }

    void clear() {

        for (int i = 0; i < MAXH; i++)
        {
            for (Edge *p = head[i], *np; p; p = np)
            {
                np = p -> next;
                delete p;
            }
            head[i] = NULL;
        }
    }
};

const int MAXN = 4;
const int MAXM = MAXN * 2 * MAXN * 2 * 2;
int n, m, mcnt;
int track[MAXM][2], dir[MAXM][2];

struct State {

    vector<string> s;

    string &operator[](int x) {

        return s[x];
    }

    int hash_value() const {

        unsigned int res = 0, res0;
        for (int i = 0; i < n; i++)
        {
            res0 = 0;
            const string &ref = s[i];
            string::size_type len = ref.length();
            for (int j = 0; j < len; j++)
                res0 = res0 * 131 + ref[j];
            res = res * 13131 + res0;
        }
        return res;
    }

    bool operator==(const State &b) const {

        for (int i = 0; i < n; i++)
            if (s[i] != b.s[i]) return false;
        return true;
    }

    void go(int n0, int d0, int n1, int d1, int k) {

        string out = s[n0].substr(0, k);
        s[n0] = s[n0].erase(0, k);
        if (d0) std::swap(out, s[n0]);
        if (d0 == d1) reverse(out.begin(), out.end());
        if (d1) s[n1] += out;
        else s[n1] = out + s[n1];
    }

    void push_back(const string &b) {

        s.push_back(b);
    }
};

struct Bfs {

    queue<State> q[2], *old, *new_;
    HashMap<State, int> hash;
    int head, tail;
    Bfs *pair;

    void init() {

        hash.clear();
        for (int i = 0; i < 2; i++)
            while (!q[i].empty()) q[i].pop();
        old = q;
        new_ = q + 1;
    }

    int push(const State &ns, int step) {

        if (hash.exist(ns)) return -1;
        if (pair -> hash.exist(ns))
        {
            int t = pair -> hash.get(ns);
            return step + t; 
        }
        hash.set(ns, step);
        new_ -> push(ns);
        return -1;
    }

    int next() {

        while (!old -> empty())
        {
            State &ref = old -> front();
            int nstep = hash.get(ref) + 1;
            for (int i = 0; i < mcnt; i++)
            {
                string::size_type len = ref[track[i][0]].length();
                for (int k = 0; k <= len; k++)
                {
                    State v = ref;
                    v.go(track[i][0], dir[i][0], track[i][1], dir[i][1], k);
                    int ret = push(v, nstep);
                    if (ret != -1) return ret;
                }
            }
            old -> pop();
        }
        swap(old, new_);
        return -1;
    }
};

Bfs ins[2];

int main() {


    for (;;)
    {
        mcnt = 0;
        scanf("%d %d", &n, &m);
        if (!n && !m) break;
        for (int i = 0; i < m; i++)
        {
            int f, t;
            char fd, td;
            scanf("%d%c %d%c", &f, &fd, &t, &td);
            fd = fd == 'E';
            td = td == 'E';
            track[mcnt][0] = f; track[mcnt][1] = t;
            dir[mcnt][0] = fd; dir[mcnt][1] = td;
            mcnt++;

            track[mcnt][0] = t; track[mcnt][1] = f;
            dir[mcnt][0] = td; dir[mcnt][1] = fd;
            mcnt++;
        }

        State root[2];
        static char buff[20];

        for (int t = 0; t < 2; t++)
        for (int i = 0; i < n; i++)
        {
            scanf("%s", buff);
            root[t].push_back(buff);
            if (root[t][i] == "-") root[t][i] = "";
        }

        for (int i = 0; i < 2; i++) 
        {
            ins[i].init();
            ins[i].pair = ins + !i;
            swap(ins[i].old, ins[i].new_);
            ins[i].push(root[i], 0);
        }
        for (int i = 0; i < 2; i++)
            swap(ins[i].old, ins[i].new_);

        for (int i = 0;; i ^= 1)
        {
            int ret = ins[i].next();
            if (ret != -1) 
            {
                printf("%d\n", ret);
                break;
            }
        }
    }

    return 0;
}
accuracy: 1
time_ms: 1790
memory_kb: 30000
final_rank: 4

code_snippet: #include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>

using namespace std;

template <class Key, class Value>
struct HashMap {

    static const int MAXH = 999983;
    struct Edge {
        Key to;
        Value v;
        Edge *next;
    } *head[MAXH];

    void set(const Key &key, const Value &value) {

        int hv = (unsigned int)key.hash_value() % MAXH;
        Edge *p = new Edge;
        p -> to = key;
        p -> v = value;
        p -> next = head[hv];
        head[hv] = p;
    }

    const Value &get(const Key &key) {

        int hv = (unsigned int)key.hash_value() % MAXH;
        for (Edge *p = head[hv]; p; p = p -> next)
            if (p -> to == key) return p -> v;
    }

    bool exist(const Key &key) {

        int hv = (unsigned int)key.hash_value() % MAXH;
        for (Edge *p = head[hv]; p; p = p -> next)
            if (p -> to == key) return true;
        return false;
    }

    void clear() {

        for (int i = 0; i < MAXH; i++)
        {
            for (Edge *p = head[i], *np; p; p = np)
            {
                np = p -> next;
                delete p;
            }
            head[i] = NULL;
        }
    }
};

const int MAXN = 4;
const int MAXM = MAXN * MAXN * 2;
int n, m, mcnt;
bool trans[MAXN][2][MAXN][2];
//int track[MAXM][2], dir[MAXM][2];

struct State {

    vector<string> s;

    string &operator[](int x) {

        return s[x];
    }

    int hash_value() const {

        unsigned int res = 0, res0;
        for (int i = 0; i < n; i++)
        {
            res0 = 0;
            const string &ref = s[i];
            string::size_type len = ref.length();
            for (int j = 0; j < len; j++)
                res0 = res0 * 131 + ref[j];
            res = res * 13131 + res0;
        }
        return res;
    }

    bool operator==(const State &b) const {

        for (int i = 0; i < n; i++)
            if (s[i] != b.s[i]) return false;
        return true;
    }

    void go(int n0, int d0, int n1, int d1, int k) {

        string out = s[n0].substr(0, k);
        s[n0] = s[n0].erase(0, k);
        if (d0) std::swap(out, s[n0]);
        if (d0 == d1) reverse(out.begin(), out.end());
        if (d1) s[n1] += out;
        else s[n1] = out + s[n1];
    }

    void push_back(const string &b) {

        s.push_back(b);
    }
};

struct Bfs {

    queue<State> q[2], *old, *new_;
    HashMap<State, int> hash;
    int head, tail;
    Bfs *pair;

    void init() {

        hash.clear();
        for (int i = 0; i < 2; i++)
            while (!q[i].empty()) q[i].pop();
        old = q;
        new_ = q + 1;
    }

    int push(const State &ns, int step) {

        if (hash.exist(ns)) return -1;
        if (pair -> hash.exist(ns))
        {
            int t = pair -> hash.get(ns);
            return step + t; 
        }
        hash.set(ns, step);
        new_ -> push(ns);
        return -1;
    }

    int next() {

        while (!old -> empty())
        {
            State &ref = old -> front();
            int nstep = hash.get(ref) + 1;
     //       for (int i = 0; i < mcnt; i++)
            for (int f = 0; f < n; f++)
                for (int t = 0; t < n; t++)
                    for (int fd = 0; fd < 2; fd++)
                        for (int td = 0; td < 2; td++)
                            if (trans[f][fd][t][td])
            {
                string::size_type len = ref[f].length();
                for (int k = 0; k <= len; k++)
                {
                    State v = ref;
                 //   v.go(track[i][0], dir[i][0], track[i][1], dir[i][1], k);
                    v.go(f, fd, t, td, k);
                    int ret = push(v, nstep);
                    if (ret != -1) return ret;
                }
            }
            old -> pop();
        }
        swap(old, new_);
        return -1;
    }
};

Bfs ins[2];

int main() {


    for (;;)
    {
        mcnt = 0;
        scanf("%d %d", &n, &m);
        if (!n && !m) break;
        memset(trans, 0, sizeof trans);
        for (int i = 0; i < m; i++)
        {
            int f, t;
            char fd, td;
            scanf("%d%c %d%c", &f, &fd, &t, &td);
            fd = fd == 'E';
            td = td == 'E';
/*            track[mcnt][0] = f; track[mcnt][1] = t;
            dir[mcnt][0] = fd; dir[mcnt][1] = td;
            mcnt++;

            track[mcnt][0] = t; track[mcnt][1] = f;
            dir[mcnt][0] = td; dir[mcnt][1] = fd;
            mcnt++;
            */
            trans[f][fd][t][td] = true;
            trans[t][td][f][fd] = true;
        }

        State root[2];
        static char buff[20];

        for (int t = 0; t < 2; t++)
        for (int i = 0; i < n; i++)
        {
            scanf("%s", buff);
            root[t].push_back(buff);
            if (root[t][i] == "-") root[t][i] = "";
        }

        for (int i = 0; i < 2; i++) 
        {
            ins[i].init();
            ins[i].pair = ins + !i;
            swap(ins[i].old, ins[i].new_);
            ins[i].push(root[i], 0);
        }
        for (int i = 0; i < 2; i++)
            swap(ins[i].old, ins[i].new_);

        for (int i = 0;; i ^= 1)
        {
            int ret = ins[i].next();
            if (ret != -1) 
            {
                printf("%d\n", ret);
                break;
            }
        }
    }

    return 0;
}
accuracy: 1
time_ms: 1720
memory_kb: 28000
final_rank: 3

code_snippet: #include<iostream>
#include<queue>
#include<string>
#include<algorithm>
#include<set>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
#define ALL(C)     (C).begin(),(C).end()
#define WEST 0
#define EAST 1

typedef unsigned long long ull;

class state{
public:
  string data[4];
  ull h[4];
  int cnt;
  state(){
    cnt=0;
    rep(i,4){data[i]="";h[i]=0;}
  }
  bool operator<(const state &a)const{
    rep(i,4)if (h[i] != a.h[i])return h[i] < a.h[i];
    return false;
  }
  bool operator==(const state &a)const{
    rep(i,4)if (h[i] != a.h[i])return false;
    return true;
  }
};

bool edge[4][4][2][2];//from to, from w or e, to w or e

const ull xxx=10007;
ull compute_hash(string &a){
  ull ret=0;
  rep(i,a.size()){
    ret=ret*xxx + a[i];
  }
  return ret;
}

inline void get_all_hash(state &a,int n){
  rep(i,n){
    a.h[i]=compute_hash(a.data[i]);
  }
}

inline void operate(string moveone,string stayone,
		    state &now,int me,int tar,
		    int dir,int tdir){
  if (dir == tdir){
    reverse(moveone.begin(),moveone.end());
  }
  if (tdir == EAST){
    now.data[tar]+=moveone;
  }else if (tdir == WEST){\
    now.data[tar]=moveone+now.data[tar];
  }
  now.data[me]=stayone;
}

void move(int n,state &now,set<state> & S,queue<state> &Q){
  rep(i,n){
    rep(j,now.data[i].size()+1){
      string tmp[2]={now.data[i].substr(0,j),now.data[i].substr(j)};
      rep(k,2){//which tmp[0] or tmp[1]
	rep(l,n){//target line
	  rep(m,2){//west or east
	    if (!edge[i][l][k][m])continue;
	    state next=now;
	    next.cnt++;
	    operate(tmp[k],tmp[1-k],next,i,l,k,m);
	    get_all_hash(next,n);
	    if (S.find(next) == S.end()){
	      S.insert(next);
	      Q.push(next);
	    }
	  }
	}
      }
    }
  }  
}

int bfs(int n,state ini,state goal,set<state> &G,bool fromstart){
  set<state> S;
  queue<state> Q;
  if (fromstart){
    Q.push(ini);
    S.insert(ini);
  }else {
    Q.push(goal);
    G.insert(goal);
  }

  while(!Q.empty()){
    state now = Q.front();
    Q.pop();
    /*
    cout <<"debug "<< fromstart << endl;
    rep(i,n){
      cout << now.data[i] << endl;
    }
    */

    if (fromstart){
      set<state>::iterator itr = G.find(now);
      if (itr != G.end())return now.cnt+(*itr).cnt;
    }else {
      if (now == ini)return now.cnt;
    }

    if (now.cnt ==3)continue;
    if (fromstart)move(n,now,S,Q);
    else move(n,now,G,Q);
  }
  return -1;
}

int solve(int n,state &ini,state &goal){
  set<state> Goal;
  int ans = bfs(n,ini,goal,Goal,false);
  if (ans != -1)return ans;
  ans=bfs(n,ini,goal,Goal,true);
  return ans;
}

main(){
  int n,m;
  while(cin>>n>>m&&n){
    rep(i,4)rep(j,4)rep(k,2)rep(l,2)edge[i][j][k][l]=false;
    rep(i,m){
      char tfd,ttd;
      int f,t;
      int fd,td;
      cin>>f>>tfd>>t>>ttd;
      if (tfd == 'W')fd=WEST;
      else fd=EAST;
      if (ttd == 'W')td=WEST;
      else td=EAST;
      edge[f][t][fd][td]=true;
      edge[t][f][td][fd]=true;
    }
    state ini,goal;
    rep(i,n){
      cin>>ini.data[i];
      if (ini.data[i] == "-")ini.data[i]="";
    }
    rep(i,n){
      cin>>goal.data[i];
      if (goal.data[i] == "-")goal.data[i]="";
    }
    get_all_hash(ini,n);
    get_all_hash(goal,n);
    
    cout << solve(n,ini,goal) << endl;
  }
}
accuracy: 1
time_ms: 6630
memory_kb: 69000
final_rank: 14