Description
Input
Output
Sample Input
2 10 20 30 1 3 2 2 4 1 1 2 2 1 2 0 0 0 0
Sample Output
30
Hint
In 3�dimensional space Manhattan distance of point A (x1, y1, z1) and B(x2, y2, z2) is |x2�x1|+|y2�y1|+|z2�z1|.
这题和D题都是最小树形图,主要会处理数据,把所有的边的可能加入树形图,然后求出最小值。在输入数据处理的时候刚开始处理得不好,T了几发,然后改用初始化列表水过了,虽然还是1587ms这么多的时间……
#include <iostream> #include <cstdio> #include <fstream> #include <algorithm> #include <cmath> #include <deque> #include <vector> #include <list> #include <queue> #include <string> #include <cstring> #include <map> #define PI acos(-1.0) #define mem(a,b) memset(a,b,sizeof(a)) #define sca(a) scanf("%d",&a) #define pri(a) printf("%d\n",a) #define M 1002 #define INF 10000000 using namespace std; typedef long long ll; struct node { int u,v,w; //边的两端结点 node() {} node(int u1,int v1,int w1):u(u1),v(v1),w(w1) {} //初始化值值列表 }e[M*M]; int pre[M],newnode[M],in[M],visit[M],a[M],b[M],c[M],n,t; //前向结点数组,新结点指向数组,边权值数组,访问数组 inline int dist(int i,int j) //坐标两点之间的距离 { return abs(a[i]-a[j])+abs(b[i]-b[j])+abs(c[i]-c[j]); } int zhuliu(int root) { int u,v,i,ans=0; //因为把环删除后其边权值是当前和与原先和之和,所以得在循环外定义 n++; while(1) { //(1).找最小边放入集合 for(i=0;i<n;i++) in[i]=INF; for(i=0;i<t;i++) { u=e[i].u; v=e[i].v; if(e[i].w<in[v]&&u!=v) { pre[v]=u; //每次都找最小边进入集合,以达最优解 in[v]=e[i].w; } } in[root]=0; for(i=0;i<n;i++) if(in[i]==INF) return -1; //除了根以外还有别的结点没有入边,则说明没有连通,无最小树形图 //(2).找环,若有环,则生成新结点,强连通分量,即环 int New=0; //新结点还是从0开始 mem(newnode,-1); mem(visit,-1); for(i=0;i<n;i++) //寻找每个结点是否有环 { ans+=in[i]; v=i; while(visit[v]!=i&&newnode[v]==-1&&v!=root) //每个点寻找其前向点,要么最终寻找至根部,要么找到一个环 { visit[v]=i; v=pre[v]; } if(v!=root&&newnode[v]==-1) //把环缩成一个点,缩点法 { for(u=pre[v];u!=v;u=pre[u]) newnode[u]=New; newnode[v]=New++; } } if(New==0) break; //如果New无变化,当然就无环啦 for(i=0;i<n;i++) if(newnode[i]==-1) newnode[i]=New++; //(3).建立新图,即把环缩成点,然后指向和边权值也随之改变 for(i=0;i<t;i++) { u=e[i].u; v=e[i].v; e[i].u=newnode[u]; e[i].v=newnode[v]; if(newnode[u]!=newnode[v]) e[i].w-=in[v]; //两个不同的结点之间的边权值改变 } n=New; root=newnode[root]; //结点更新之后,根结点可能有环而改变,所以根结点也要更新 } return ans; } int main() { int i,j,x,y,z,m,ab; //把所有可能的结点与边都加入最小树形图中 while(scanf("%d%d%d%d",&n,&x,&y,&z)&&(n||x||y||z)) { for(i=1,t=0;i<=n;i++) //结点从1开始 { scanf("%d%d%d",&a[i],&b[i],&c[i]); e[t++]=node(0,i,c[i]*x); } for(i=1;i<=n;i++) { for(j=0,sca(m);j<m;j++) { sca(ab); if(ab==i) continue; //下一句:结点从1开始 int d=dist(i,ab)*y; e[t++]=(c[i]>=c[ab]?node(i,ab,d):node(i,ab,d+z)); } } int ans=zhuliu(0); ans==-1?printf("poor XiaoA\n"):pri(ans); } return 0; }