/*找到除根节点之外,其他点的权值最小的入边
如果有环的话就进行缩点,形成新图,更新其他点到环上的点的距离
直到没有环为止, 至于更新其他点到环上的点的距离看了这遍文章懂了
如果有环的话就进行缩点,形成新图,更新其他点到环上的点的距离
直到没有环为止, 至于更新其他点到环上的点的距离看了这遍文章懂了
http://blog.csdn.net/sdj222555/article/details/7459738*/
#include<string.h>
#include<stdio.h>
#include<algorithm>
#include<cmath>
using namespace std;
#define clr(a,b) (memset(a,b,sizeof(a)))
const int NV=1111;
const int NE =1111111;
const int I=0x7f7f7f7f;
struct node1{
int u,v,val;
}E[NE];
struct node2{
int x,y,z;
}point[1111];
int dis(int x,int y)
{
return abs(point[x].x-point[y].x)+abs(point[x].y-point[y].y)+abs(point[x].z-point[y].z);
}
int pre[NV],mi[NV],id[NV],vis[NV];//id表示缩点后新点,
int mst(int root,int nv,int ne)
{
int i,u,v,ret=0;
while(true)
{
clr(mi,0x7f);
mi[root]=0;
for(i=0;i<ne;i++)
{
u=E[i].u;
v=E[i].v;
if(u!=v&&mi[v]>E[i].val)
{
mi[v]=E[i].val;
pre[v]=u;//u指向v;
}
}//
/*for(i=0;i<nv;i++)
if(mi[i]==I) return -1;*/// 如果找不到最小入边,就不能形成树形图
int cnt=0;
clr(id,-1);
clr(vis,-1);
for(i=0;i<nv;i++)
{
ret+=mi[i];
for(v=i;v!=root;v=pre[v])
{
if(vis[v]==i||id[v]!=-1) break;
vis[v]=i;
}
if(v!=root&&id[v]==-1) //如果有环的话,就进行缩点
{
for(u=pre[v];u!=v;u=pre[u])
{
id[u]=cnt;
}
id[v]=cnt++;
}//缩点
}
if(cnt==0) break;// 如果没有环
for(i=0;i<nv;i++)
if(id[i]==-1) id[i]=cnt++;
for(i=0;i<ne;i++)
{
v=E[i].v;
E[i].u=id[E[i].u];//把缩点后的新点赋值给新边集中
E[i].v=id[E[i].v];
if(E[i].u!=E[i].v)
E[i].val-=mi[v];//更新其他点到环上的点的距离
}
nv=cnt;
root=id[root];//把根节点所在的那个缩点之后形成的新点作为根节点
}
return ret;
}
int main()
{
int n,x,y,z;
while(scanf("%d%d%d%d",&n,&x,&y,&z),n+x+y+z)
{
int cnt=0;
for(int i=1;i<=n;i++)
scanf("%d%d%d",&point[i].x,&point[i].y,&point[i].z);
for(int i=1;i<=n;i++)
{
int k;
scanf("%d",&k);
while(k--)
{
int j;
scanf("%d",&j);
if(i==j) continue;
E[cnt].u=i,E[cnt].v=j;
E[cnt].val=y*dis(i,j);
if(point[i].z<point[j].z)
{
E[cnt].val+=z;
}
cnt++;
}
}
for(int i=1;i<=n;i++)
{
E[cnt].u=0;
E[cnt].v=i;
E[cnt].val=point[i].z*x;
cnt++;
}
int ans=mst(0,n+1,cnt);
printf("%d\n",ans);
}
return 0;
}