PKU3013Big Christmas Tree(SPFA+queue+邻接表)

做了几道PKU上的图论,感觉PKU上的图论题很坑人。都是属于比较不易理解,且变化丰富的。这样也好,被虐多了,或许感觉就慢慢来了。3013,做了一两天了。表示累透了~~此题一上来第一反应就是图论,可是当我花了不少时间彻底理解了题目后,却发现有点儿不像图论,怪怪的,毛毛的,下面会解释。

题意

        某人过圣诞节,要买个圣诞树,然后正常的想要尽量花最小的钱达到要求。这个图是一棵倒着的树,每一条边都有单价,每个节点也由各自的重量,边与边的单价由于形状不一样,单价也不一样,其实就是做最短路的“权值”啦,但是这道题又有点儿BT,它算整棵树的价值不是权值相加。

        重点:它是这样来算每条边的总价的。每条边的总价==(这条边的单价)X(以这条边的尾结点为根节点的那棵树的所有节点的重量之和)。还是很难理解?举个小例子:例如下面这个图中的边2-3,那么这条边2-3的总价值是它的(单价)X(节点5的重量+节点7的重量+节点6的重量+节点3的重量)。因为以3为根节点的树的所有节点为:5,7,6,3,嘛。。

然后这道题如何跟最短路扯上关系?题意已经理解清楚了,可是还是有毛毛的感觉。不知道从何入手。

解题思路:(以1-2表示节点1到节点2的边哦,5表示节点5的重量,以此类推)

              动手画一画,发挥你的数学功底。想想哦,总价值的公式为:(1-2)X(2+4+3+5+6+7)+(2-4)X4+(2-3)X(3+5+6+7)+(3-5)X5+(3-7)X7+(3-6)X6。然后提取公因式,把相同边都提取出来,式子就变成了从节点1到每个节点的最短路径X该节点的重量。哈哈,是不是有想法了?

这样就能用一般的最短路处理了。

题的烦恼

              题超BT,说神马各个值<2^16次方,那么就表示,有可能用来存放dis[]的数组的值会超过int型而溢出,所以dis[]只能用__int64来存放,结果ans也要用__int64.好吧,这里让我郁闷了好久好久。还有就是主函数的输入用邻接表来存储的时候,我因为每个结构体的起始点弄错而纠结,唉,肿么最近老是变量看错啊。

代码:

#include<iostream> 
using namespace std; 
 
const int MAXV=70001
const __int64 infinity=0xfffffffffffff;//最大值要用__int64 
 
struct edge 

    int u; 
    int v; 
    int w; 
    int next; 
}edge[MAXV*2]; 
 
int nv,ne; 
int arrHead[MAXV],queue[MAXV*2],val[MAXV]; 
__int64 dis[MAXV];//dis[]也得用__int64,int会溢出的 
bool visited[MAXV]; 
 
void spfa(int s) 

    int i,head,top,u,v,w; 
    for(i=1;i<=nv;i++) 
    { 
        dis[i]=infinity;//存每个点的最短路 
        visited[i]=0
    } 
    top=1,head=0
    queue[top]=s; 
    dis[s]=0
    //SPFA的经典队列 
    while(head<top) 
    { 
        head=(head+1)%MAXV; 
        u=queue[head]; 
        visited[u]=0
        for(i=arrHead[u];i!=-1;i=edge[i].next) 
        { 
            v=edge[i].v,w=edge[i].w; 
            if(dis[v]>dis[u]+w) 
            { 
                dis[v]=dis[u]+w; 
                if(!visited[v]) 
                { 
                    top=(top+1)%MAXV; 
                    queue[top]=v; 
                    visited[v]=1
                } 
            } 
        } 
    } 
 
    __int64 ans; 
    //从节点1到每个节点的最短路X每个节点的重量的总和即为圣诞树的总价值 
    for(i=2,ans=0;i<=nv;i++) 
    { 
        if(dis[i]==infinity) 
        { 
            cout<<"No Answer"<<endl; 
            break
        } 
        ans+=dis[i]*val[i]; 
    } 
    if(i>nv) 
        cout<<ans<<endl; 
    return ; 

 
int main(void

    int cas,szEdge,s,e,w,i; 
    scanf("%d",&cas); 
    while(cas--) 
    { 
        scanf("%d%d",&nv,&ne);//节点,边 
        memset(arrHead,-1,sizeof(arrHead));//注意如果这里用for初始化的话,要考虑nv=0的情况 
        for(i=1;i<=nv;i++) 
            scanf("%d",&val[i]);//节点的重量 
        szEdge=0
        for(i=1;i<=ne;i++)//邻接表输入 
        { 
            szEdge++; 
            scanf("%d%d%d",&s,&e,&w);//边以及边的单价 
            edge[szEdge].u=s; 
            edge[szEdge].v=e; 
            edge[szEdge].w=w; 
            edge[szEdge].next=arrHead[s]; 
            arrHead[s]=szEdge; 
 
            szEdge++; 
            edge[szEdge].u=e; 
            edge[szEdge].v=s; 
            edge[szEdge].w=w; 
            edge[szEdge].next=arrHead[e]; 
            arrHead[e]=szEdge; 
        } 
        spfa(1); 
    } 
    return 0

      

原文地址:https://www.cnblogs.com/cchun/p/2520122.html