poj 3013(数组模拟邻接表+spfa)

88 篇文章 0 订阅

     首先,自已先用数组模拟邻接链表,以前使用模版的,现在可以不看模版自己写了。。。

    边的信息:

struct EDGE
{
    int   u;//起点
    int   v;//终点
    lint  len;//边的长度
    int next;
}edge[MAX*3+1];//一定要边的范围

int head [MAX];//头节点

void init()//初始化信息,-1;
{
    for(int i=1;i<=n;i++)
    head[i]=-1;
    k=1;
}

插入边

void insert(int u,int v,__int64 len)
{
  edge[k].v=v; edge[k].len=len; edge[k].next=head[u];head[u]=k;k++;//正边
  edge[k].v=u; edge[k].len=len; edge[k].next=head[v];head[v]=k;k++;//反边
}


遍历:for(int i=head[top];i!=-1;i=edge[i].next)

然后看题意:

有一些点,每个点都有一个重量值,然后给出了一些边,每个边都有一个权值最后让用一些边组成一棵树,使得花费最少,每个边(u,v)的花费=(边得所有子孙节点的重量和)*(该边的权值)对于这个花费,可以看出,对于每条边(u,v),其花费就相当于每个在后面的结点都走了这个边一次,那么我们可以假想,已经形成了最优的树,观察这颗树,就能发现,对于一条边(u,v),由于边的子女都走了这条边一次,而且是在一棵树中,那么从根结点到边的某个子女结点的路径必然包含(u,v),其他边同理,那么所有边的花费之和,就可以转化为(从根结点到某个结点的路径长度*结点重量)之和   那么之后就是求最短路径了。

注意:某些地方会超过int,所以开long long 就好了,INF的值也设的大一些。比如100亿,因为最短路径的极限数据应该是50000*2^16>2^31


代码:

 

#include <iostream>
#include <cstring>
#include <queue>
#include <cstdio>
using namespace std;
const int MAX=50001;
typedef unsigned long long lint;
const long long  INF=999999999;
struct EDGE
{
    int   u;
    int   v;
    lint  len;
    int next;
}edge[MAX*3+1];


int head [MAX];
lint weight[MAX];
lint  dist[MAX];
bool  vis[MAX];
lint  n;
int k=1;


void init()
{
    for(int i=1;i<=n;i++)
    head[i]=-1;
    k=1;
}


void insert(int u,int v,__int64 len)
{
  edge[k].v=v; edge[k].len=len; edge[k].next=head[u];head[u]=k;k++;
  edge[k].v=u; edge[k].len=len; edge[k].next=head[v];head[v]=k;k++;
}


void spfa(int s)
{
   memset(vis,0,sizeof(vis));
   for(int i=1;i<=n;i++)
   dist[i]=INF;


   dist[s]=0;
   queue<int>qu;
   qu.push(s);


   while(!qu.empty())
   {
       int top=qu.front();
       qu.pop();
       vis[top]=0;
       for(int i=head[top];i!=-1;i=edge[i].next)
       {
          if(dist[edge[i].v]>dist[top]+edge[i].len)
          {
              dist[edge[i].v]=dist[top]+edge[i].len;
              if(!vis[edge[i].v])
              {
                  vis[edge[i].v]=1;
                  qu.push(edge[i].v);
              }
          }
       }
   }
}


int main()
{
    int cas;
    scanf("%d",&cas);
    while(cas--)
    {
      lint  m;
      scanf("%I64d%I64d",&n,&m);
      init();
      for(int i=1;i<=n;i++)
      scanf("%I64d",&weight[i]);


      int u,v;
      lint c;
      for(int i=0;i<m;i++)
      {
          scanf("%d%d",&u,&v);
          scanf("%I64d",&c);
          insert(u,v,c);
      }
      spfa(1);
      int flag=1;
      lint  sum=0;
      for(int i=1;i<=n;i++)
      {
        if(dist[i]==INF)
        {
          flag=0;break;
        }
        sum+=weight[i]*dist[i];
      }
      if(flag)
      printf("%d\n",sum);
      else
      printf("No Answer\n");
    }
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值