#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<utility>
#include<cassert>
using namespace std;

typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
const ll mod = 1000000007;
const ll INF = mod * mod;
typedef pair<int, int> P;
#define stop char nyaa;cin>>nyaa;
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
typedef pair<ll, ll> LP;
typedef vector<int> vec;
typedef vector<string> svec;
typedef long double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-8;


struct poly {
	vector<int> c;
	poly(vector<int> v) {
		c = v;
	}
	poly(int x) {
		c = { x };
	}
	poly() {};
};

bool operator<(const poly &a, const poly &b) {
	if (a.c.size() != b.c.size())return a.c.size() < b.c.size();
	per(i, (int)a.c.size()) {
		if (a.c[i] != b.c[i])return a.c[i] < b.c[i];
	}
	return false;
}
poly operator-(const poly &a, const poly &b) {
	poly ret;
	int len = max(a.c.size(), b.c.size());
	ret.c.resize(len);
	rep(i, len) {
		int s = 0;
		if (i < a.c.size())s += a.c[i];
		if (i < b.c.size())s -= b.c[i];
		ret.c[i]=s;
	}
	while (ret.c.size() > 1 && ret.c.back() == 0)ret.c.pop_back();
	return ret;
}
poly operator+(const poly &a, const poly &b) {
	poly ret;
	int len = max(a.c.size(), b.c.size());
	ret.c.resize(len,0);
	rep(i, len) {
		int s = 0;
		if (i < a.c.size())s += a.c[i];
		if (i < b.c.size())s += b.c[i];
		ret.c[i]=s;
	}
	while (ret.c.size() > 1 && ret.c.back() == 0)ret.c.pop_back();
	return ret;
}
bool operator==(const poly &a, const poly &b) {
	return a.c == b.c;
}
poly min(poly a, poly b) {
	if (a < b)return a;
	return b;
}
poly in() {
	poly ret; ret.c.resize(52, 0);
	string s; cin >> s;
	int loc = 0;
	rep(i, s.length()) {
		if (s[i] == '+') {
			string t = s.substr(loc, i - loc);
			int c = 1;
			if (isdigit(t[0])) {
				int j = 0;
				while (j < t.length() && isdigit(t[j]))j++;
				c = stoi(t.substr(0, j));
			}
			bool f = false;
			int d = 1;
			rep(j, t.length()) {
				if (t[j] == 'x') {
					f = true;
				}
				if (t[j] == '^') {
					int le = j + 1;
					j++;
					while (j < t.length() && isdigit(t[j]))j++;
					d = stoi(t.substr(le, j - le));
				}
			}
			if (!f)d = 0;
			ret.c[d] = c;
			loc = i + 1;
		}
	}
	string t = s.substr(loc, t.length() - loc);
	int c = 1;
	if (isdigit(t[0])) {
		int j = 0;
		while (j < t.length() && isdigit(t[j]))j++;
		c = stoi(t.substr(0, j));
	}
	bool f = false;
	int d = 1;
	rep(j, t.length()) {
		if (t[j] == 'x') {
			f = true;
		}
		if (t[j] == '^') {
			int le = j + 1;
			j++;
			while (j < t.length() && isdigit(t[j]))j++;
			d = stoi(t.substr(le, j - le));
		}
	}
	if (!f)d = 0;
	ret.c[d] = c;
	while (ret.c.size() > 1 && ret.c.back() == 0)ret.c.pop_back();
	return ret;
}
void out(poly p) {
	if (p == 0) {
		cout << 0 << endl; return;
	}
	string ret;
	per(i, (int)p.c.size()) {
		if (p.c[i]) {
			if (i == 0 && p.c[i] == 1) {
				ret.push_back('1');
			}
			if (p.c[i] != 1) {
				string z = to_string(p.c[i]);
				ret += z;
			}
			if (i >= 1) {
				ret.push_back('x');
				if (i > 1) {
					ret.push_back('^');
					string z = to_string(i);
					ret += z;
				}
			}
			ret.push_back('+');
		}
	}
	ret.pop_back();
	cout << ret << endl;
}


struct edge { int to; poly cap; int rev; };


vector<edge> G[100000];
bool used[100000];
void add_edge(int from, int to, poly cap) {
	G[from].push_back(edge{ to, cap, (int)G[to].size() });
	G[to].push_back(edge{ from, 0, (int)G[from].size() - 1 });
}
poly dfs(int v, int t, poly f) {
	if (v == t)return f;
	used[v] = true;
	for (int i = 0; i < (int)G[v].size(); i++) {
		edge &e = G[v][i];
		if (!used[e.to] && 0<e.cap) {
			poly d = dfs(e.to, t, min(f, e.cap));
			if (0<d) {
				e.cap = e.cap-d;
				G[e.to][e.rev].cap = G[e.to][e.rev].cap+d;
				return d;
			}
		}
	}
	return 0;
}
const poly inf(vector<int>(52, 1));
poly max_flow(int s, int t,int sz) {
	poly flow = 0;
	for (;;) {
		fill(used, used + sz, false);
		poly f = dfs(s, t, inf);
		//out(f);
		if (f == poly(0))return flow;
		flow = flow+f;
		//out(flow);
	}
}
bool isdigit(char t) {
	return '0' <= t && t <= '9';
}
int n, m;
void solve() {
	rep(i, n)G[i].clear();
	rep(i, m) {
		int a, b; cin >> a >> b; a--; b--;
		poly p = in();
		add_edge(a, b, p);
		add_edge(b, a, p);
	}
	poly ans = max_flow(0, n - 1,n);
	//cout << "ans is ";
	out(ans);
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);

	//cout << fixed << setprecision(10);
	//init();
	while(cin>>n>>m,n)solve();
	//stop
		return 0;
}


Measured memory_bytes: 6012