poj-3013 透过现象看本质,其实都一样

来源:互联网 发布:python newspaper 编辑:程序博客网 时间:2024/05/19 04:02

这道题目咋一看就是最小生成树啊。

题目描述大概是这样:

KCm要准备一颗圣诞树,这棵树有一些节点和边组成。节点从1到n,根总是1.每个节点都有自己的总量,而边的价格是由边的单价乘以子孙节点的重量。

求出这么一颗有n个节点的树,使花费最小。

 

很像最小生成树,仔细研究,没法这样做。因为每条边在找到这颗树之前很难计算它的价值。

因为本来你算好的边的价值,但是在去掉某些边时,会导致边的价值发生变化,那怎么办。。。。

 

这道题目开始我也是不知道怎么计算,看到discuss说是最短路。试想最后已经得到一个树,而每条边的价值就是子孙节点重量和乘以单价,可以转换为,此节点重量乘以从根到本节点的最短路,这么一转化,问题瞬间变得简单了。

 

那么所有点的最短路径一定是一棵树吗?   这个是显然的 ,因为如果形成环了,到达某个点就出现了多个路径,就要删去长的那条,使其没有环

 

样例中的计算方法
4*40+3*50+2*60+3*(20+40+50+60)+2*30+1*(10+20+30+40+50+60)
=10*1+20*(1+3)+30*(2+1)+40*(4+1+3)+50*(3+1+3)+60*(1+2+3)
=10+80+90+320+350+360
=1210

 

题目要注意几个地方

1、n=0或者1, 答案是0,而不是no answer

2、数据范围大,要用long long

3、n=0或者1的时候也要将数据读入,不能直接输出0就不管输入了,否则会re

4、注意是无向图,建邻接表的时候要双向

5、数据量大,邻接矩阵不行,必须邻接表

 

搞清楚了这些,剩下就是简单的spfa了

代码:

#include<stdio.h>#define maxN 50005#define inf 10000000000000struct EDGE {int v,w;int next;}edge[2 * maxN];//邻接表int preEdge[2 * maxN];//preEdge[u],上一条以u为起点的边在edge中的位置long long dis[maxN];//最短路bool vis[maxN];int weight[maxN];//节点重量int queue[20 * maxN];//松弛队列int n,m;void Init()//初始化{for (int i = 1; i <= n; ++ i){preEdge[i] = 0;dis[i] = inf;vis[i] = false;}}void spfa(){int head = 0, tail = 1;queue[0] = 1;dis[1] = 0;while (head < tail){int u = queue[head];vis[u] = true;int p = preEdge[u];//以u为起始点 邻接表中第几条边while (p != 0){int v = edge[p].v, w = edge[p].w;if (dis[v] > dis[u] + w){dis[v] = dis[u] + w;if (!vis[v]){vis[v] = true;queue[tail] = v;tail ++;}}p = edge[p].next;//下一条以u起点的边}head ++;vis[u] = false;}bool flag = true;long long  sum = 0;for (int i = 2; i <= n; ++ i){if (dis[i] == inf){flag = false;break;}sum += weight[i] * dis[i];}if (!flag){printf("No Answer\n");}elseprintf("%lld\n", sum);}int main(){int t;scanf("%d", &t);while (t --){scanf("%d%d", &n, &m);for (int i = 1; i <= n; ++ i){scanf("%d", &weight[i]);}Init();int index = 1;for (int i = 1; i <= m; ++ i){int a, b, c;scanf("%d%d%d", &a, &b, &c);edge[index].v = b;edge[index].w = c;edge[index].next = preEdge[a];preEdge[a] = index ++;edge[index].v = a;edge[index].w = c;edge[index].next = preEdge[b];preEdge[b] = index ++;}if (n == 0 || n == 1){printf("0\n");continue;}spfa();}return 0;}


 

 

原创粉丝点击