Problem:
KND Factory

Problem

KND君は会津大学に在籍する学生プログラマである。彼の住む町の周辺には N 個の町がある。彼は生クリームが大好きなので毎日生クリームを食べるためにある町に工場を建設した。その工場では毎日 F リットルの生クリームが製造される。生クリームは運ぶたびに、移動元の町の気温と移動先の町の気温の絶対差だけ傷んでしまう。困ったことにこの近辺の町の気温は寒暖計によって計測できない。しかしながら調査によって、それぞれの町の気温を変数とした N 個の一次方程式からなる N 元一次連立方程式を導くことができた。あなたはこれを解くことによって各町の気温を知ることができる。また、ある町から他の町へ生クリームを運搬するにはパイプラインを用いる。パイプラインは一日に送ることのできる生クリームの量が限られている。一日に F リットルの生クリームを工場がある町 s からKND君が住む町 t へ生クリームをなるべく良い状態で送りたい。町には0から始まる番号がつけられているものとする。方程式の各項は高々ひとつの変数からなり定数項がひとつある。 F リットルの生クリームはどのような運び方をしても一日以内で任意の町へ送られる。

Input

入力は複数のテストケースからなる。ひとつのテストケースは以下の形式で与えられる。テストケースの数は入力として与えられる。

T
N s t F
a1,1 a1,2 ... a1,N c1
a2,1 a2,2 ... a2,N c2
...
aN,1 aN,2 ... aN,N cN
M1
d1,1 d1,2 ... d1,M1
f1,1 f1,2 ... f1,M1
M2
d2,1 d2,2 ... d2,M2
f2,1 f2,2 ... f2,M2
...
MN
dN,1 dN,2 ... dN,M2
fN,1 fN,2 ... fN,M2

ここで、

T:テストケースの数

N:町の数

s:工場のある町

t:KND君の住む町

F:一日に作られる生クリームの量

ai,j:連立方程式の未知数としてのi番目の方程式中でj番目の町の気温にかかる係数。もしai,j=0ならj番目の町の気温はこの方程式に現れないことになる。以下の例も参照してほしい。

ci:i番目の方程式の定数項

Mi:i番目の町が持っている生クリームを移動させる機械の数

di,j:i番目の町が持っているj番目の機械が生クリームを移動させる先の町

fi,j:i番目の町が持っているj番目の機械が生クリームを1日に移動させられるリットル量

である。

N元一次連立方程式を表す行列の入力例:

a + b = 6 1 1 0 6
3a + 2b + c = 10 => 3 2 1 10
a - 2b + 3c = 6 1 -2 3 6

a,b,cが町0,1,2の気温を表す。

Constraints

入力は以下の条件を満たす。

入力はすべて整数。

0 < T ≤ 40

2 < N ≤ 100

0 ≤ s < N

0 ≤ t < N

s ≠ t

0 < F ≤ 1000

0 ≤ Mi ≤ N

-1000 ≤ ai,j ≤ 1000

0 ≤fi,j< 1000

それぞれの町の気温は一意に定まる。

Output

各テストケースにつき、一日に F リットルの生クリームを工場がある町 s からKND君が住む町 t に運んだとき、生クリームの傷みの和を最小化した値を一行で出力せよ。この値はジャッジ出力の値と10-5より大きい差を持ってはならない。また、町 s から町 t へ F リットルの生クリームを一日に運べない場合はimpossibleを一行で出力せよ。

Sample Input

3
3 0 2 5
1 1 1 6
3 2 1 10
1 -2 3 6
2
1 2
3 3
1
2
3
0
3 0 2 5
1 1 1 6
3 2 1 10
1 -2 3 6
2
1 2
2 2
1
2
2
0
10 2 7 20
8 9 -5 6 -9 5 1 0 4 9 4
3 -1 -8 0 -5 4 3 0 -3 2 4
-4 5 8 -4 1 -8 -6 3 3 5 -7
-7 0 2 5 8 -5 -9 -8 1 -2 -1
3 8 1 -3 8 2 -5 8 -3 4 -4
-2 5 0 -2 -4 4 -3 9 6 -1 -2
4 1 2 -9 3 5 6 -4 4 -1 -4
-4 6 6 9 -2 1 -9 -3 -7 3 -4
1 -1 6 3 1 -5 9 5 -5 -9 -5
-7 4 6 8 8 4 -4 4 -7 -8 -5
5
1 5 0 6 3
15 17 14 7 15
3
1 5 7
6 8 14
10
3 5 3 5 9 5 9 5 1 4
12 6 16 11 16 7 9 3 13 13
10
9 1 5 6 2 5 8 5 9 4
15 8 8 14 13 13 18 1 12 11
5
3 5 0 4 6
14 15 4 14 11
9
5 0 6 2 7 8 8 6 6
6 5 7 17 17 17 17 19 3
9
7 7 2 7 8 4 7 7 0
4 13 16 10 19 17 19 12 19
3
1 5 1
3 7 16
8
5 7 4 9 1 4 6 8
4 3 6 12 6 19 10 1
4
1 3 6 3
5 15 18 14

Sample Output

10.0000000000
impossible
11.9354380207

Solution in C++ (judge verdict: Accepted)

#include<algorithm>
#include<cassert>
#include<cctype>
#include<climits>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<iomanip>
#include<map>
#include<numeric>
#include<queue>
#include<vector>
#include<set>
#include<string>
#include<stack>
#include<sstream>
#include<complex>

#define pb push_back
#define clr clear()
#define sz size()
#define fs first
#define sc second

#define rep(i,a) for(int i=0;i<(int)(a);i++)
#define rrep(i,a) for(int i=(int)(a)−1;i>=0;i−−)
#define all(a) (a).begin(),(a).end()
#define EQ(a,b) (abs((a)−(b)) < EPS)
#define INIT(a) memset(a,0,sizeof(a))

using namespace std;
typedef long double D;
typedef pair<int,int> P;
typedef long long ll;
typedef vector<int> vi;
typedef vector<string> vs;

const D EPS = 1e-7;
const D INF = 1e10;
const D PI = acos(-1);

typedef vector<D> vec;
typedef vector<vec> mat;

struct matrix{
  mat m;
  int r,c;
  matrix(void){r=c=0;m.clr;}
  matrix(mat a){
    r = a.sz; c = a[0].sz;
    m.resize(r);
    rep(i,r)m[i].resize(c);
    rep(i,r)rep(j,c)m[i][j] = a[i][j];
  }

  matrix operator+(matrix a){
    if(r==a.r && c==a.c){
      rep(i,r)rep(j,c)a.m[i][j] += m[i][j];
    }
    return a;
  }

  matrix operator-(matrix a){
    rep(i,a.r)rep(j,a.c)a.m[i][j] *= -1;
    return *this+a;
  }

  matrix operator*(matrix a){
    matrix x;
    if(c==a.r){
      x.r = r; x.c = a.c;
      x.m.resize(r);
      rep(i,r)x.m[i].resize(a.c);
      rep(i,r)rep(j,a.c){
	x.m[i][j] = 0;
	rep(k,c)x.m[i][j] += m[i][k] * a.m[k][j];
      }
    }
    return x;
  }
};

vec gauss_jordan(const mat& A, const vec& b){
  int n = A.size();
  mat B(n,vec(n+1));
  rep(i,n)rep(j,n)B[i][j] = A[i][j];
  rep(i,n)B[i][n] = b[i];
  rep(i,n){
    int p=i;
    for(int j=i;j<n;j++)
      if(abs(B[j][i]) > abs(B[p][i]))p = j;
    swap(B[i],B[p]);
    //解か&#12441;ないか、一意て&#12441;ない
    if(abs(B[i][i]) < EPS)return vec();
    for(int j=i+1;j<=n;j++)B[i][j] /= B[i][i];
    rep(j,n)
      if(i != j)
	for(int k=i+1;k<=n;k++)B[j][k] -= B[j][i] * B[i][k];
  }
  vec x(n);
  rep(i,n)x[i] = B[i][n];
  return x;
}

int T;
int N,s,t,F;
mat a;
vec b;

//辺の定義。必要に応し&#12441;て削る。
struct edge{
  int from,to,cap,rev;
  D cost;
  edge(int a=0,int b=0,D c=0,int d=0,int e=0):from(a),to(b),cost(c),cap(d),rev(e){}
};
int v; //ク&#12441;ラフの頂点数
vector<edge> G[110]; //ク&#12441;ラフの隣接リスト表現

//辺の追加。2つ目の辺の追加はフローアルコ&#12441;リス&#12441;ムの残余ク&#12441;ラフ用。 
void AddEdge(int s,int g, D c,int p){
  G[s].pb(edge(s,g,c,p,G[g].sz));
  G[g].pb(edge(g,s,-c,0,G[s].sz-1));
}

D d[110];
int pv[110],pe[110]; //直前の頂点と辺
D primal_dual(int s,int t, int f){
  D res = 0;
  while(f>0){
    /*
    rep(i,v){
      cout << "-----" << i << "-----" << endl;
      rep(j,G[i].sz){
	cout << G[i][j].to << " " << G[i][j].cost << " " << G[i][j].cap << endl;
      }
    }
    */

    fill(d,d+v,INF);
    d[s] = 0;
    bool update = true;
    while(update){
      update = false;
      rep(u,v){
	if(d[u]==INF)continue;
	rep(i,G[u].sz){
	  edge &e = G[u][i];
	  if(e.cap > 0 && d[e.to] > d[u] + e.cost + EPS){
	    d[e.to] = d[u] + e.cost;
	    pv[e.to] = u; pe[e.to] = i;
	    update = true;
	  }
	}
      }
    }

    if(d[t] == INF)return -1;

    int x=f;
    for(int u=t;u!=s;u=pv[u]){
      x = min(x,G[pv[u]][pe[u]].cap);
    }
    f-=x;
    res += x*d[t];
    for(int u=t;u!=s;u=pv[u]){
      edge &e = G[pv[u]][pe[u]];
      e.cap -= x;
      G[u][e.rev].cap += x;
    }
  }
  return res;
}

int M[110];
int to[110][110], f[110][110]; 

int main(){
  cin >> T;
  while(T--){
    cin >> N >> s >> t >> F;
    a.resize(N); b.resize(N);
    rep(i,N){
      a[i].resize(N);
      rep(j,N)cin >> a[i][j];
      cin >> b[i];
      G[i].clr;
    }

    vec temp = gauss_jordan(a,b);

    //rep(i,N)cout << temp[i] << " "; cout << endl;

    rep(i,N){
      cin >> M[i];
      rep(j,M[i])cin >> to[i][j];
      rep(j,M[i])cin >> f[i][j];

      rep(j,M[i]){
	AddEdge(i,to[i][j],abs(temp[i]-temp[to[i][j]]),f[i][j]);
      }
    }

    v = N;
    D ans = primal_dual(s,t,F);
    if(ans < EPS)cout << "impossible" << endl;
    else cout << fixed << setprecision(10) << ans << endl;
  }
}