Problem:


Problem I: Mobile Network

The trafic on the Internet is increasing these days due to smartphones. The wireless carriers
have to enhance their network infrastructure.

The network of a wireless carrier consists of a number of base stations and lines. Each line connects two base stations bi-directionally. The bandwidth of a line increases every year and is given by a polynomial f(x) of the year x.

Your task is, given the network structure, to write a program to calculate the maximal bandwidth between the 1-st and N-th base stations as a polynomial of x.

Input

The input consists of multiple datasets. Each dataset has the following format:

N M

u1 v1 p1

...

uM vM pM

The first line of each dataset contains two integers N (2 ≤ N ≤ 50) and M (0 ≤ M ≤ 500), which indicates the number of base stations and lines respectively. The following M lines describe the network structure. The i-th of them corresponds to the i-th network line and contains two integers ui and vi and a polynomial pi. ui and vi indicate the indices of base stations (1 ≤ ui, vi ≤ N); pi indicates the network bandwidth.

Each polynomial has the form of:

aLxL + aL-1xL-1 + ... + a2x2 + a1x + a0

where L (0 ≤ L ≤ 50) is the degree and ai's (0 ≤ i ≤ L, 0 ≤ ai ≤ 100) are the coefficients. In the input,

each term aixi (for i ≥ 2) is represented as <ai>x^<i>

the linear term (a1x) is represented as <a1>x;

 the constant (a0) is represented just by digits;

 these terms are given in the strictly decreasing order of the degrees and connected by a
plus sign ("+");

 just like the standard notations, the <ai> is omitted if ai = 1 for non-constant terms;

 similarly, the entire term is omitted if ai = 0 for any terms; and

the polynomial representations contain no space or characters other than digits, "x", "^", and "+".

For example, 2x2 + 3x + 5 is represented as 2x^2+3x+5; 2x3 + x is represented as 2x^3+x, not 2x^3+0x^2+1x+0 or the like. No polynomial is a constant zero, i.e. the one with all the coefficients being zero.

The end of input is indicated by a line with two zeros. This line is not part of any dataset.

Output

For each dataset, print the maximal bandwidth as a polynomial of x. The polynomial should be represented in the same way as the input format except that a constant zero is possible and should be represented by "0" (without quotes).

Sample Input

3 3
1 2 x+2
2 3 2x+1
3 1 x+1
2 0
3 2
1 2 x
2 3 2
4 3
1 2 x^3+2x^2+3x+4
2 3 x^2+2x+3
3 4 x+2
0 0

Output for the Sample Input

2x+3
0
2
x+2



Sample input:
3 3
1 2 x+2
2 3 2x+1
3 1 x+1
2 0
3 2
1 2 x
2 3 2
4 3
1 2 x^3+2x^2+3x+4
2 3 x^2+2x+3
3 4 x+2
0 0


Sample output:
2x+3
0
2
x+2

Submission status: Accepted

Solution code:
import collections


def plus_list(A, B):
    assert(len(A) == len(B))
    return [a + b for a, b in zip(A, B)]


def minus_list(A, B):
    assert(len(A) == len(B))
    return [a - b for a, b in zip(A, B)]


def gt_list(A, B):
    assert(len(A) == len(B))
    for a, b in zip(A, B):
        if a != b:
            return a > b
    return False


class MaxFlow:
    """Dinic Algorithm: find max-flow
       complexity: O(EV^2)
       used in GRL6A(AOJ)
    """
    class Edge:
        def __init__(self, to, cap, rev):
            self.to, self.cap, self.rev = to, cap, rev

    def __init__(self, V, D):
        """ V: the number of vertexes
            E: adjacency list
            source: start point
            sink: goal point
        """
        self.V = V
        self.E = [[] for _ in range(V)]
        self.D = D

    def add_edge(self, fr, to, cap):
        self.E[fr].append(self.Edge(to, cap, len(self.E[to])))
        self.E[to].append(self.Edge(fr, [0] * self.D, len(self.E[fr])-1))

    def dinic(self, source, sink):
        """find max-flow"""
        INF = [10**9] * self.D
        maxflow = [0] * self.D
        while True:
            self.bfs(source)
            if self.level[sink] < 0:
                return maxflow
            self.itr = [0] * self.V
            while True:
                flow = self.dfs(source, sink, INF)
                if gt_list(flow, [0] * self.D):
                    maxflow = plus_list(maxflow, flow)
                else:
                    break

    def dfs(self, vertex, sink, flow):
        """find augmenting path"""
        if vertex == sink:
            return flow
        for i in range(self.itr[vertex], len(self.E[vertex])):
            self.itr[vertex] = i
            e = self.E[vertex][i]
            if gt_list(e.cap, [0] * self.D) and self.level[vertex] < self.level[e.to]:
                if gt_list(flow, e.cap):
                    d = self.dfs(e.to, sink, e.cap)
                else:
                    d = self.dfs(e.to, sink, flow)
                if gt_list(d, [0] * self.D):
                    e.cap = minus_list(e.cap, d)
                    self.E[e.to][e.rev].cap = plus_list(self.E[e.to][e.rev].cap, d)
                    return d
        return [0] * self.D

    def bfs(self, start):
        """find shortest path from start"""
        que = collections.deque()
        self.level = [-1] * self.V
        que.append(start)
        self.level[start] = 0

        while que:
            fr = que.popleft()
            for e in self.E[fr]:
                if gt_list(e.cap, [0] * self.D) and self.level[e.to] < 0:
                    self.level[e.to] = self.level[fr] + 1
                    que.append(e.to)


def to_poly(a, l):
    if l == 0:
        return str(a)
    elif l == 1:
        return "{}x".format('' if a == 1 else a)
    else:
        return "{}x^{}".format('' if a == 1 else a, l)

while True:
    N, M = map(int, input().split())
    if N == M == 0:
        break
    mf = MaxFlow(N, 51)
    for _ in range(M):
        u, v, p = input().split()
        u, v = int(u)-1, int(v)-1
        poly = [0] * 51
        for x in p.split('+'):
            try:
                num = int(x)
                poly[-1] = num
            except ValueError:
                a, l = x.split('x')
                if l:
                    poly[-int(l.strip("^"))-1] = int(a) if a else 1
                else:
                    poly[-2] = int(a) if a else 1
        mf.add_edge(u, v, poly)
        mf.add_edge(v, u, poly)
    maxflow = mf.dinic(0, N-1)
    ans = '+'.join(to_poly(a, l) for a, l in zip(maxflow, reversed(range(51))) if a)
    print(ans if ans else 0)

Submission status: Accepted

Solution code:
import collections


class MyList(list):
    def __init__(self, x=[]):
        list.__init__(self, x)

    def __iadd__(self, A):
        ret = MyList()
        for a, b in zip(self, A):
            ret.append(a + b)
        return ret

    def __isub__(self, A):
        ret = MyList()
        for a, b in zip(self, A):
            ret.append(a - b)
        return ret

    def __gt__(self, A):
        for a, b in zip(self, A):
            if a != b:
                return a > b
        return False


class MaxFlow:
    """Dinic Algorithm: find max-flow
       complexity: O(EV^2)
       used in GRL6A(AOJ)
    """
    class Edge:
        def __init__(self, to, cap, rev):
            self.to, self.cap, self.rev = to, cap, rev

    def __init__(self, V, D):
        """ V: the number of vertexes
            E: adjacency list
            source: start point
            sink: goal point
        """
        self.V = V
        self.E = [[] for _ in range(V)]
        self.D = D

    def zero(self):
        return MyList([0] * self.D)

    def add_edge(self, fr, to, cap):
        self.E[fr].append(self.Edge(to, cap, len(self.E[to])))
        self.E[to].append(self.Edge(fr, self.zero(), len(self.E[fr])-1))

    def dinic(self, source, sink):
        """find max-flow"""
        INF = MyList([10**9] * self.D)
        maxflow = self.zero()
        while True:
            self.bfs(source)
            if self.level[sink] < 0:
                return maxflow
            self.itr = MyList([0] * self.V)
            while True:
                flow = self.dfs(source, sink, INF)
                if flow > self.zero():
                    maxflow += flow
                else:
                    break

    def dfs(self, vertex, sink, flow):
        """find augmenting path"""
        if vertex == sink:
            return flow
        for i in range(self.itr[vertex], len(self.E[vertex])):
            self.itr[vertex] = i
            e = self.E[vertex][i]
            if e.cap > self.zero() and self.level[vertex] < self.level[e.to]:
                if flow > e.cap:
                    d = self.dfs(e.to, sink, e.cap)
                else:
                    d = self.dfs(e.to, sink, flow)
                if d > self.zero():
                    e.cap -= d
                    self.E[e.to][e.rev].cap += d
                    return d
        return self.zero()

    def bfs(self, start):
        """find shortest path from start"""
        que = collections.deque()
        self.level = [-1] * self.V
        que.append(start)
        self.level[start] = 0

        while que:
            fr = que.popleft()
            for e in self.E[fr]:
                if e.cap > self.zero() and self.level[e.to] < 0:
                    self.level[e.to] = self.level[fr] + 1
                    que.append(e.to)


def to_poly(a, l):
    if l == 0:
        return str(a)
    elif l == 1:
        return "{}x".format('' if a == 1 else a)
    else:
        return "{}x^{}".format('' if a == 1 else a, l)

while True:
    N, M = map(int, input().split())
    if N == M == 0:
        break
    mf = MaxFlow(N, 51)
    for _ in range(M):
        u, v, p = input().split()
        u, v = int(u)-1, int(v)-1
        poly = MyList([0] * 51)
        for x in p.split('+'):
            try:
                num = int(x)
                poly[-1] = num
            except ValueError:
                a, l = x.split('x')
                if l:
                    poly[-int(l.strip("^"))-1] = int(a) if a else 1
                else:
                    poly[-2] = int(a) if a else 1
        mf.add_edge(u, v, poly)
        mf.add_edge(v, u, poly)
    maxflow = mf.dinic(0, N-1)
    ans = '+'.join(to_poly(a, l) for a, l in zip(maxflow, reversed(range(51))) if a)
    print(ans if ans else 0)

Submission status: Accepted

Solution code:
import collections


class MyList(list):
    def __init__(self, x=[]):
        list.__init__(self, x)

    def __iadd__(self, A):
        return MyList([a + b for a, b in zip(self, A)])

    def __isub__(self, A):
        return MyList([a - b for a, b in zip(self, A)])

    def __gt__(self, A):
        for a, b in zip(self, A):
            if a != b:
                return a > b
        return False


class MaxFlow:
    """Dinic Algorithm: find max-flow
       complexity: O(EV^2)
       used in GRL6A(AOJ)
    """
    class Edge:
        def __init__(self, to, cap, rev):
            self.to, self.cap, self.rev = to, cap, rev

    def __init__(self, V, D):
        """ V: the number of vertexes
            E: adjacency list
            source: start point
            sink: goal point
        """
        self.V = V
        self.E = [[] for _ in range(V)]
        self.D = D

    def zero(self):
        return MyList([0] * self.D)

    def add_edge(self, fr, to, cap):
        self.E[fr].append(self.Edge(to, cap, len(self.E[to])))
        self.E[to].append(self.Edge(fr, self.zero(), len(self.E[fr])-1))

    def dinic(self, source, sink):
        """find max-flow"""
        INF = MyList([10**9] * self.D)
        maxflow = self.zero()
        while True:
            self.bfs(source)
            if self.level[sink] < 0:
                return maxflow
            self.itr = MyList([0] * self.V)
            while True:
                flow = self.dfs(source, sink, INF)
                if flow > self.zero():
                    maxflow += flow
                else:
                    break

    def dfs(self, vertex, sink, flow):
        """find augmenting path"""
        if vertex == sink:
            return flow
        for i in range(self.itr[vertex], len(self.E[vertex])):
            self.itr[vertex] = i
            e = self.E[vertex][i]
            if e.cap > self.zero() and self.level[vertex] < self.level[e.to]:
                if flow > e.cap:
                    d = self.dfs(e.to, sink, e.cap)
                else:
                    d = self.dfs(e.to, sink, flow)
                if d > self.zero():
                    e.cap -= d
                    self.E[e.to][e.rev].cap += d
                    return d
        return self.zero()

    def bfs(self, start):
        """find shortest path from start"""
        que = collections.deque()
        self.level = [-1] * self.V
        que.append(start)
        self.level[start] = 0

        while que:
            fr = que.popleft()
            for e in self.E[fr]:
                if e.cap > self.zero() and self.level[e.to] < 0:
                    self.level[e.to] = self.level[fr] + 1
                    que.append(e.to)


def to_poly(a, l):
    if l == 0:
        return str(a)
    elif l == 1:
        return "{}x".format('' if a == 1 else a)
    else:
        return "{}x^{}".format('' if a == 1 else a, l)

while True:
    N, M = map(int, input().split())
    if N == M == 0:
        break
    mf = MaxFlow(N, 51)
    for _ in range(M):
        u, v, p = input().split()
        u, v = int(u)-1, int(v)-1
        poly = MyList([0] * 51)
        for x in p.split('+'):
            try:
                num = int(x)
                poly[-1] = num
            except ValueError:
                a, l = x.split('x')
                if l:
                    poly[-int(l.strip("^"))-1] = int(a) if a else 1
                else:
                    poly[-2] = int(a) if a else 1
        mf.add_edge(u, v, poly)
        mf.add_edge(v, u, poly)
    maxflow = mf.dinic(0, N-1)
    ans = '+'.join(to_poly(a, l) for a, l in zip(maxflow, reversed(range(51))) if a)
    print(ans if ans else 0)

Submission status: Accepted

Solution code:
import collections
import sys
if sys.version[0] == '2':
    input, range = raw_input, xrange


class MyList(list):
    def __init__(self, x=[]):
        list.__init__(self, x)

    def __iadd__(self, A):
        return MyList([a + b for a, b in zip(self, A)])

    def __isub__(self, A):
        return MyList([a - b for a, b in zip(self, A)])

    def __gt__(self, A):
        for a, b in zip(self, A):
            if a != b:
                return a > b
        return False


class MaxFlow:
    """Dinic Algorithm: find max-flow
       complexity: O(EV^2)
       used in GRL6A(AOJ)
    """
    class Edge:
        def __init__(self, to, cap, rev):
            self.to, self.cap, self.rev = to, cap, rev

    def __init__(self, V, D):
        """ V: the number of vertexes
            E: adjacency list
            source: start point
            sink: goal point
        """
        self.V = V
        self.E = [[] for _ in range(V)]
        self.D = D

    def zero(self):
        return MyList([0] * self.D)

    def add_edge(self, fr, to, cap):
        self.E[fr].append(self.Edge(to, cap, len(self.E[to])))
        self.E[to].append(self.Edge(fr, self.zero(), len(self.E[fr])-1))

    def dinic(self, source, sink):
        """find max-flow"""
        INF = MyList([10**9] * self.D)
        maxflow = self.zero()
        while True:
            self.bfs(source)
            if self.level[sink] < 0:
                return maxflow
            self.itr = MyList([0] * self.V)
            while True:
                flow = self.dfs(source, sink, INF)
                if flow > self.zero():
                    maxflow += flow
                else:
                    break

    def dfs(self, vertex, sink, flow):
        """find augmenting path"""
        if vertex == sink:
            return flow
        for i in range(self.itr[vertex], len(self.E[vertex])):
            self.itr[vertex] = i
            e = self.E[vertex][i]
            if e.cap > self.zero() and self.level[vertex] < self.level[e.to]:
                if flow > e.cap:
                    d = self.dfs(e.to, sink, e.cap)
                else:
                    d = self.dfs(e.to, sink, flow)
                if d > self.zero():
                    e.cap -= d
                    self.E[e.to][e.rev].cap += d
                    return d
        return self.zero()

    def bfs(self, start):
        """find shortest path from start"""
        que = collections.deque()
        self.level = [-1] * self.V
        que.append(start)
        self.level[start] = 0

        while que:
            fr = que.popleft()
            for e in self.E[fr]:
                if e.cap > self.zero() and self.level[e.to] < 0:
                    self.level[e.to] = self.level[fr] + 1
                    que.append(e.to)


def to_poly(a, l):
    if l == 0:
        return str(a)
    elif l == 1:
        return "{}x".format('' if a == 1 else a)
    else:
        return "{}x^{}".format('' if a == 1 else a, l)

while True:
    N, M = map(int, input().split())
    if N == M == 0:
        break
    mf = MaxFlow(N, 51)
    for _ in range(M):
        u, v, p = input().split()
        u, v = int(u)-1, int(v)-1
        poly = MyList([0] * 51)
        for x in p.split('+'):
            try:
                num = int(x)
                poly[-1] = num
            except ValueError:
                a, l = x.split('x')
                if l:
                    poly[-int(l.strip("^"))-1] = int(a) if a else 1
                else:
                    poly[-2] = int(a) if a else 1
        mf.add_edge(u, v, poly)
        mf.add_edge(v, u, poly)
    maxflow = mf.dinic(0, N-1)
    ans = '+'.join(to_poly(a, l) for a, l in zip(maxflow, reversed(range(51))) if a)
    print(ans if ans else 0)

Submission status: Accepted

Solution code:
import sys
readline = sys.stdin.readline
write = sys.stdout.write
from string import digits

from collections import deque
class Dinic:
    def __init__(self, N):
        self.N = N
        self.G = [[] for i in range(N)]

    def add_edge(self, fr, to, cap):
        forward = [to, cap, None]
        forward[2] = backward = [fr, 0, forward]
        self.G[fr].append(forward)
        self.G[to].append(backward)

    def add_multi_edge(self, v1, v2, cap1, cap2):
        edge1 = [v2, cap1, None]
        edge1[2] = edge2 = [v1, cap2, edge1]
        self.G[v1].append(edge1)
        self.G[v2].append(edge2)

    def bfs(self, s, t):
        self.level = level = [None]*self.N
        deq = deque([s])
        level[s] = 0
        G = self.G
        while deq:
            v = deq.popleft()
            lv = level[v] + 1
            for w, cap, _ in G[v]:
                if cap and level[w] is None:
                    level[w] = lv
                    deq.append(w)
        return level[t] is not None

    def dfs(self, v, t, f):
        if v == t:
            return f
        level = self.level
        for e in self.it[v]:
            w, cap, rev = e
            if cap and level[v] < level[w]:
                d = self.dfs(w, t, min(f, cap))
                if d:
                    e[1] -= d
                    rev[1] += d
                    return d
        return 0

    def flow(self, s, t):
        flow = 0
        INF = 10**9 + 7
        G = self.G
        while self.bfs(s, t):
            *self.it, = map(iter, self.G)
            f = INF
            while f:
                f = self.dfs(s, t, INF)
                flow += f
        return flow

def parse(S, L=50):
    S = S + "$"
    E = [0]*(L+1)
    cur = 0
    while 1:
        if S[cur] in digits:
            k = 0
            while S[cur] in digits:
                k = 10*k + int(S[cur])
                cur += 1 # '0' ~ '9'
        else:
            k = 1
        if S[cur] == 'x':
            cur += 1 # 'x'
            if S[cur] == '^':
                cur += 1 # '^'
                p = 0
                while S[cur] in digits:
                    p = 10*p + int(S[cur])
                    cur += 1 # '0' ~ '9'
            else:
                p = 1
        else:
            p = 0
        E[p] = k
        if S[cur] != '+':
            break
        cur += 1 # '+'
    return E

def solve():
    N, M = map(int, readline().split())
    if N == 0:
        return False
    L = 50
    ds = [Dinic(N) for i in range(L+1)]
    for i in range(M):
        u, v, p = readline().split()
        u = int(u)-1; v = int(v)-1
        poly = parse(p, L)
        for j in range(L+1):
            if poly[j] > 0:
                ds[j].add_multi_edge(u, v, poly[j], poly[j])
    INF = 10**9
    res = [0]*(L+1)
    for j in range(L+1):
        f = ds[j].flow(0, N-1)
        res[j] = f
    E = [[0]*N for i in range(N)]
    for j in range(L-1, -1, -1):
        d = ds[j]
        used = [0]*N
        used[N-1] = 1
        que = deque([N-1])
        G = ds[j+1].G
        for v in range(N):
            for w, cap, _ in G[v]:
                if cap:
                    E[v][w] = 1
        for v in range(N):
            for w in range(N):
                if E[v][w]:
                    d.add_edge(v, w, INF)
        f = d.flow(0, N-1)
        res[j] += f
    ans = []
    if res[0] > 0:
        ans.append(str(res[0]))
    if res[1] > 0:
        ans.append(("%dx" % res[1]) if res[1] > 1 else "x")
    for i in range(2, L+1):
        if res[i] > 0:
            ans.append(("%dx^%d" % (res[i], i)) if res[i] > 1 else ("x^%d" % i))
    if not ans:
        ans.append("0")
    ans.reverse()
    write("+".join(ans))
    write("\n")
    return True
while solve():
    ...