HDU 4009 Transfer water 【最小树形图】
模板题,不解释。详细介绍请见百度百科 http://baike.baidu.com/view/5944982.htm或者1963年的刘朱算法论文(谁有啊?求个链接)。
复杂度O(V*E)。模板详见胡浩NotOnlySuccess大牛的blog( http://www.notonlysuccess.com/?p=315)。
本题添加一个树根,连到所有点,边权为每点的打井费用,其他套模板。
附代码,顺便感谢hh大牛和戴牛!!!
#include
<
iostream
>
#include < cstdio >
#include < cstring >
using namespace std;
#define maxn 1005
#define type int
const int inf = ~ 0u >> 1 ;
struct node
{
int u,v;
type cost;
node(){}
node( int _u, int _v,type _c):u(_u),v(_v),cost(_c){}
}e[maxn * maxn];
int pre[maxn],id[maxn],vis[maxn];
type in [maxn];
type dirmst( int root, int nv, int ne)
{
type ret = 0 ;
while ( 1 )
{
// find the smallest in-arc
fill( in , in + nv,inf);
for ( int i = 0 ;i < ne;i ++ )
{
int u = e[i].u;
int v = e[i].v;
if (e[i].cost < in [v] && u != v)
{
pre[v] = u;
in [v] = e[i].cost;
}
}
for ( int i = 0 ;i < nv;i ++ )
{
if (i == root)
continue ;
if ( in [i] == inf)
return - 1 ; // there are some nodes other than root with no in-arc connected to it
}
// find the dir circle
int cntnode = 0 ;
fill(id,id + nv, - 1 );
fill(vis,vis + nv, - 1 );
in [root] = 0 ;
for ( int i = 0 ;i < nv;i ++ )
{
ret += in [i];
int v = i;
while (vis[v] != i && id[v] == - 1 && v != root)
{
vis[v] = i;
v = pre[v];
}
if (v != root && id[v] == - 1 )
{
for ( int u = pre[v]; u != v;u = pre[u])
id[u] = cntnode;
id[v] = cntnode ++ ;
}
}
if (cntnode == 0 )
break ; // no circle
for ( int i = 0 ;i < nv;i ++ )
if (id[i] == - 1 )
id[i] = cntnode ++ ;
// compress the nodes
for ( int i = 0 ;i < ne;i ++ )
{
int 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].cost -= in [v];
}
nv = cntnode;
root = id[root];
}
return ret;
}
int n,tot,X,Y,Z;
int ab( int x)
{
return x >= 0 ? x: - x;
}
struct point
{
int x,y,z;
point(){}
point( int a, int b, int c):x(a),y(b),z(c){}
point operator - ( const point p)
{
return point(x - p.x,y - p.y,z - p.z);
}
int dis()
{
return ab(x) + ab(y) + ab(z);
}
}p[maxn];
int main()
{
while (scanf( " %d %d %d %d " , & n, & X, & Y, & Z) == 4 && (n || X || Y || Z))
{
tot = 0 ;
for ( int i = 1 ;i <= n;i ++ )
{
int a,b,c;
scanf( " %d %d %d " , & a, & b, & c);
p[i] = point(a,b,c);
e[tot ++ ] = node( 0 ,i,ab(p[i].z) * X);
}
for ( int i = 1 ;i <= n;i ++ )
{
int opt;
scanf( " %d " , & opt);
for ( int j = 0 ;j < opt;j ++ )
{
int a;
scanf( " %d " , & a);
if (a == i)
continue ;
int temp = Y * (p[i] - p[a]).dis();
if (p[i].z < p[a].z)
temp += Z;
e[tot ++ ] = node(i,a,temp);
}
}
int ans = dirmst( 0 ,n + 1 ,tot);
if (ans == - 1 )
puts( " poor XiaoA " );
else
printf( " %d\n " ,ans);
}
}
#include < cstdio >
#include < cstring >
using namespace std;
#define maxn 1005
#define type int
const int inf = ~ 0u >> 1 ;
struct node
{
int u,v;
type cost;
node(){}
node( int _u, int _v,type _c):u(_u),v(_v),cost(_c){}
}e[maxn * maxn];
int pre[maxn],id[maxn],vis[maxn];
type in [maxn];
type dirmst( int root, int nv, int ne)
{
type ret = 0 ;
while ( 1 )
{
// find the smallest in-arc
fill( in , in + nv,inf);
for ( int i = 0 ;i < ne;i ++ )
{
int u = e[i].u;
int v = e[i].v;
if (e[i].cost < in [v] && u != v)
{
pre[v] = u;
in [v] = e[i].cost;
}
}
for ( int i = 0 ;i < nv;i ++ )
{
if (i == root)
continue ;
if ( in [i] == inf)
return - 1 ; // there are some nodes other than root with no in-arc connected to it
}
// find the dir circle
int cntnode = 0 ;
fill(id,id + nv, - 1 );
fill(vis,vis + nv, - 1 );
in [root] = 0 ;
for ( int i = 0 ;i < nv;i ++ )
{
ret += in [i];
int v = i;
while (vis[v] != i && id[v] == - 1 && v != root)
{
vis[v] = i;
v = pre[v];
}
if (v != root && id[v] == - 1 )
{
for ( int u = pre[v]; u != v;u = pre[u])
id[u] = cntnode;
id[v] = cntnode ++ ;
}
}
if (cntnode == 0 )
break ; // no circle
for ( int i = 0 ;i < nv;i ++ )
if (id[i] == - 1 )
id[i] = cntnode ++ ;
// compress the nodes
for ( int i = 0 ;i < ne;i ++ )
{
int 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].cost -= in [v];
}
nv = cntnode;
root = id[root];
}
return ret;
}
int n,tot,X,Y,Z;
int ab( int x)
{
return x >= 0 ? x: - x;
}
struct point
{
int x,y,z;
point(){}
point( int a, int b, int c):x(a),y(b),z(c){}
point operator - ( const point p)
{
return point(x - p.x,y - p.y,z - p.z);
}
int dis()
{
return ab(x) + ab(y) + ab(z);
}
}p[maxn];
int main()
{
while (scanf( " %d %d %d %d " , & n, & X, & Y, & Z) == 4 && (n || X || Y || Z))
{
tot = 0 ;
for ( int i = 1 ;i <= n;i ++ )
{
int a,b,c;
scanf( " %d %d %d " , & a, & b, & c);
p[i] = point(a,b,c);
e[tot ++ ] = node( 0 ,i,ab(p[i].z) * X);
}
for ( int i = 1 ;i <= n;i ++ )
{
int opt;
scanf( " %d " , & opt);
for ( int j = 0 ;j < opt;j ++ )
{
int a;
scanf( " %d " , & a);
if (a == i)
continue ;
int temp = Y * (p[i] - p[a]).dis();
if (p[i].z < p[a].z)
temp += Z;
e[tot ++ ] = node(i,a,temp);
}
}
int ans = dirmst( 0 ,n + 1 ,tot);
if (ans == - 1 )
puts( " poor XiaoA " );
else
printf( " %d\n " ,ans);
}
}