/*
copy http://hi.baidu.com/matrush/blog/item/4a8f1d3c430e773370cf6cd4.html
題意:給定n(n<=5)個必選點,和m(m<=1000)個輔助點,每個點有權值,以及帶權無向邊若干,求一棵代價最小的生成子樹,使得n個必選點連通并且總權值最小。
分析:這題比較巧妙,首先因為又有邊權又有點權不好處理,所以我們先建一個虛擬點0,
把所有點與0點連邊,邊權為該點的點權,那么就轉化成了有n+m+1個點,
求出這些點中使0-n這n+1個點連通的最小生成樹。這個定義其實就是所謂的斯坦納樹。
Steiner Tree是NP的,但是當必選點較少時,可以通過狀態壓縮DP來解,
具體的DP狀態是dp[x][1<<m] 代表以x為根的樹并且包含state里的點的最小權值。
那么求一棵樹就可以枚舉連接點,以及兩個子樹的覆蓋狀態,通過一個很漂亮的轉移方程來進行轉移:
dp[i][j]=min(dp[i][j],dp[i][k]+dp[i][j^k]),其中k是j的一個子集,而這個子集又可以通過位運算枚舉子集來實現:
for (int sub = state;sub != 0;sub = (sub-1) & state)
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int MAXN = 1010;
const int INF = 1000000000;
struct Edge
{
int u,v,w;
Edge *next;
};
//dp[x][1<<m] 代表以x為根的樹并且包含state里的點的最小費用
int dp[MAXN][1<<6];
int dist[MAXN][MAXN];
int chg[MAXN];
Edge edges[MAXN*20] , *E[MAXN] , *pE;
bool inQ[MAXN];
void init(int n)
{
pE = edges;
for(int i=0;i<=n;i++)E[i] = NULL;
}
inline void addE(int u,int v,int w)
{
pE->v = v;
pE->w = w;
pE->next = E[u];
E[u] = pE++;
}
void spfa(int now,int n)
{
fill(inQ,inQ+n+1,false);
fill(dist[now],dist[now]+n+1,INF);
queue<int>Q;
Q.push(now);
inQ[now] = 1;
dist[now][now] = 0;
while(!Q.empty())
{
int u = Q.front();
Q.pop();
inQ[u] = 0;
for( Edge *it = E[u]; it ;it = it->next)
{
int v = it->v,w=it->w;
if(dist[now][v] > dist[now][u] + w)
{
dist[now][v] = dist[now][u] + w;
if(!inQ[v])
{
inQ[v] = true;
Q.push(v);
}
}
}
}
}
int steiner(int m,int n,int chg[])//[0,m] [0,n] 0~n共n個點里面選出p中的m個點
{
for(int i=0;i<=n;i++)
{
spfa(i,n);
}
for(int i=0;i<=m;i++)
for(int j=0;j<=n;j++)
dp[j][1<<i] = dist[chg[i]][j];
int limit = 1<<(m+1);
for(int state = 1; state < limit; state++)
{
if((state - 1) & state)//二進制不止一個1
{
for(int j = 0; j<=n; j++)
{
dp[j][state] = INF;
for(int _state = (state-1) & state ; _state ; _state = (_state-1) & state) //枚舉子集
dp[j][state] = min(dp[j][state] , dp[j][_state] + dp[j][_state ^ state]);
}
for(int j=0;j<=n;j++)
for(int k=0;k<=n;k++)
dp[j][state] = min(dp[j][state],dp[k][state] + dist[k][j]);
}
}
return dp[0][limit-1];
}
int main()
{
#ifdef ONLINE_JUDGE
#else
freopen("in","r",stdin);
#endif
int n,m,p;
while( ~scanf("%d%d%d",&n,&m,&p))
{
init(n+m);
for(int i=1,val;i<=n+m;i++)
{
scanf("%d",&val);
addE(i,0,val);
addE(0,i,val);
}
for(int i=0,u,v,w;i<p;i++)
{
scanf("%d%d%d",&u,&v,&w);
addE(u,v,w);
addE(v,u,w);
}
for(int i=0;i<=n+m;i++)chg[i] = i;
printf("%d\n",steiner(n,n+m,chg));
}
return 0;
}