前前后后调了几个小时,交了 30 30 30发…
原来板子是没错的,但是如果虚根是 0 0 0
那么每次的编号就要从 0 0 0起
对应的 v i s vis vis和 i d id id数组就不能判断是否为 0 0 0
每次更新点数也要变化…
下次绝对不用下标 0 0 0的了…我吐了
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e6+10;
const int inf = 2e9;
int n,m,root,X,Y,Z,top;
int x[maxn],y[maxn],z[maxn];
int dis(int l,int r)
{
return abs(x[l]-x[r])+abs(y[l]-y[r])+abs(z[l]-z[r]);
}
struct edge{
int u,v,w;
}a[maxn];
int pre[maxn],inw[maxn],id[maxn],vis[maxn];
int zhuliu(int root,int n)
{
int ans=0;
while( 1 )
{
for(int i=1;i<=n;i++) inw[i]=inf;
for(int i=1; i<=top ;i++)
{
int u=a[i].u,v=a[i].v;
if( u!=v&&a[i].w<inw[v] )//为每个点找最小入边
inw[v]=a[i].w,pre[v]=u;
}
for(int i=1;i<=n;i++)//没有入边就无解
if( i!=root&&inw[i]==inf ) return -1;
int cnt=0;
for(int i=1;i<=n;i++) vis[i]=id[i]=0;
for(int i=1;i<=n;i++)
{
if( i==root ) continue;
ans+=inw[i];
int v=i;
//首先vis[i]!=i是避免重复走环,!id[v]是不能走到之前的环去
//v!=root因为root没有入边,可以退出了
while( vis[v]!=i&&v!=root&&!id[v] )
vis[v]=i,v=pre[v];
if( !id[v]&&v!=root )//没走到根节点,说明有环
{
id[v]=++cnt;//标记环中的点
for(int u=pre[v];u!=v;u=pre[u] )
id[u]=cnt;
}
}
if( cnt==0 ) break;//无环,是最小树形图
for(int i=1;i<=n;i++)
if( !id[i] ) id[i]=++cnt;
for(int i=1;i<=top;i++)
{
int u=a[i].u,v=a[i].v;
a[i].u=id[u],a[i].v=id[v];//缩点
if( id[u]!=id[v] ) a[i].w-=inw[v];//修改边权
}
root=id[root];
n=cnt;
}
return ans;
}
int main()
{
while( scanf("%d%d%d%d",&n,&X,&Y,&Z )!=EOF&&(n+X+Y+Z) )
{
top = 0;
for(int i=1;i<=n;i++)
scanf("%d%d%d",&x[i],&y[i],&z[i] );
for(int i=1;i<=n;i++)
{
int k; scanf("%d",&k);
for(int j=1;j<=k;j++)
{
int id; scanf("%d",&id);
a[++top].u = i, a[top].v = id;
if( z[i]>=z[id] ) a[top].w = dis(i,id)*Y;
else a[top].w = dis(i,id)*Y+Z;
}
}
for(int i=1;i<=n;i++)
a[++top].u = n+1, a[top].v = i, a[top].w = z[i]*X;
int ans = zhuliu(n+1,n+1);
cout << ans << endl;
}
}