斯坦纳树
#include<cstdio>
#include<cstring>
#include<queue>
#define N 210
#define M 5100
using namespace std;
int a[N],b[N];
int a1[N],b1[N];
int st[N],dp[N][1000],ans[1000];
bool vis[N][1000];
struct Edge{
int v,w,next;
}edge[M*2];
int n,m,k,K,ans2;
int head[N],cnt;
queue<int>q;
void addedge(int u,int v,int w){
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].next=head[u];
head[u]=cnt++;
edge[cnt].v=u;
edge[cnt].w=w;
edge[cnt].next=head[v];
head[v]=cnt++;
}
void init(){
memset(head,-1,sizeof(head));
memset(st,0,sizeof(st));
memset(dp,-1,sizeof(dp));
memset(vis,0,sizeof(vis));
memset(ans,-1,sizeof(ans));
cnt=0;
}
void SPFA(){
int i;
while(!q.empty()){
int x=q.front()/10000,y=q.front()%10000;
vis[x][y]=0;
q.pop();
for(i=head[x];i!=-1;i=edge[i].next){
int v=edge[i].v;
if(dp[v][st[v]|y]==-1 || dp[v][st[v]|y]>dp[x][y]+edge[i].w){
dp[v][st[v]|y]=dp[x][y]+edge[i].w;
if(!vis[v][st[v]|y] && (st[v]|y)==y){
vis[v][st[v]|y]=1;
q.push(v*10000+(st[v]|y)); //一定要加括号
}
}
}
}
}
void Steiner_Tree(){
int i,j,p,x;
for(p=0;p<K;p++){
for(i=1;i<=n;i++){
if(st[i] && (st[i]&p)==0)continue;
for(x=(p-1)&p;x;x=(x-1)&p)
if(dp[i][x|st[i]]!=-1 && dp[i][(p-x)|st[i]]!=-1)
if(dp[i][p]==-1 || (dp[i][p]>dp[i][x|st[i]]+dp[i][(p-x)|st[i]]))
dp[i][p]=dp[i][x|st[i]]+dp[i][(p-x)|st[i]];
if(dp[i][p]!=-1){
q.push(i*10000+p);
vis[i][p]=1;
}
}
SPFA();
}
}
bool check(int u){
int i,a2=0,b2=0;
for(i=0;i<k;i++)
if(u&(1<<i)){
a2+=a1[i];
b2+=b1[i];
}
return b2<=a2;
}
int cout(int u){
int i,a2=0,b2=0;
for(i=0;i<k;i++)
if(u&(1<<i)){
a2+=a1[i];
b2+=b1[i];
}
return min(a2,b2);
}
void solve(){
int i,j;
int num=0,ans1=0;
for(i=0;i<K;i++)
for(j=1;j<=n;j++)
if(dp[j][i]!=-1)
if(ans[i]==-1 || ans[i]>dp[j][i])
ans[i]=dp[j][i];
for(i=0;i<K;i++){
//if(check(i)){ //这里只需去找那些工厂大于等于resource planets个数的状态即可
for(j=(i-1)&i;j;j=(j-1)&i)
if((check(i) && check(j) && check(i-j)) || (!check(i) && !check(j) && !check(i-j))) //或者找划分中工厂个数与resource planets个数不等式同方向的
if(ans[j]!=-1 && ans[i-j]!=-1)
if(ans[i]==-1 || ans[i]>ans[j]+ans[i-j])
ans[i]=ans[j]+ans[i-j];
int cou=cout(i);
if(ans[i]!=-1) //一定要加这个判断
if(cou>num || (cou==num && ans[i]<ans1))
num=cou,ans1=ans[i];
//}
}
printf("%d %d\n",num/*+ans2*/,ans1);
}
int main(){
int i,u,v,w;
while(scanf("%d",&n)==1){
k=ans2=0;
init();
for(i=1;i<=n;i++){
scanf("%d %d",&a[i],&b[i]);
/*if(a[i]&&b[i]){
a[i]--;
b[i]--;
ans2++;
}*/
if(a[i]||b[i]){
a1[k]=a[i],b1[k]=b[i];
st[i]=1<<(k++);
dp[i][st[i]]=0;
}
}
K=1<<k;
scanf("%d",&m);
for(i=1;i<=m;i++){
scanf("%d %d %d",&u,&v,&w);
addedge(u,v,w);
}
Steiner_Tree();
solve();
}
return 0;
}