POJ1511 SPFA经典题目

Orz,做这道题对我这个初学者来说真是呕心沥血了!写了一上午,然后调试了一下午。然后WA了3次!哇靠,就是因为坑爹的POJ数据,题目明白说了price的sum不会超int的

但最后还是要用long long 才过!奶娘的! 在这里感谢羽哥的数据还有long long的提醒。

 

题目大意:发传单!怎么样选择路线 使得Acmers们在去  和回的过程 花掉的车费最少。

思路:因为每个人负责一站,其实人在这里只是幌子,只要找出出发点到每个站的最短路径(就是最少花费),那么每个人的的花费总和也会最小。回来的时候同理

因为在这里的数据很大。V、 E都达到100W,用朴素的dijkstra已经不行,用堆优化的,我不会(囧)。bellman 算法也不可行了。因为是O(VE)效率。只能选择O(kE)的SPFA算法了(k<=2)

 

PS:    SPFA判断有无负环很简单,就是:用一个数组记录每个节点的入队次数,如果入队次数到达节点总数N那么就有负权环。

 

program:

 

#include<cstdio>
#include<queue>
#include<iostream>
#include<string.h>
using namespace std;
#define maxn 1000005
#define inf 1500000000
int visited[maxn],dis[maxn],st[maxn];
int test,n,m;
int u[maxn],v[maxn],w[maxn];
struct node
{
  int x;
  int value;
  int next;
}e[maxn];
void spfa() // int
{
  for(int i=1;i<=n;i++)
  {
     visited[i]=0;//杯具啊,一开始写成1了。囧 
     dis[i]=inf;      
  }
  visited[1]=1;
  dis[1]=0;
  queue<int>que;
  que.push(1);
  int tmp=st[1];
  int cur;
  int k=0;
 
  while(!que.empty())
  {
    cur=que.front();
    tmp=st[cur]; // 同样Qrz,一开始竟然没有。囧
    que.pop();
    visited[cur]=0;       //一出队就重新吧标志擦去,这是SPFA和BFS最大的区别,下面基本上和BFS的相似度极大
    while(tmp!=0)
    { 
     
       if(dis[e[tmp].x]>dis[cur]+e[tmp].value)
       {
          dis[e[tmp].x]=dis[cur]+e[tmp].value;
          if(visited[e[tmp].x]==0)
             {
                que.push(e[tmp].x);
                visited[e[tmp].x]=1;
               // printf("                 e[tmp].x %d   \n",e[tmp].x) ;               
             }                                   
       }
    //  printf("tmp e[tmp].next %d  %d   \n",tmp,e[tmp].next) ;
      tmp=e[tmp].next;
        
    }                                   
  }
  
}
void ini()
{
  memset(e,0,sizeof(e));
  memset(st,0,sizeof(st)); 
  for(int i=1;i<=m;i++)
  {
      
      e[i].x=v[i];
      e[i].value=w[i];
      e[i].next=st[u[i]];
      st[u[i]]=i;
      //printf("i e[i].next %d  %d   \n",i,e[i].next) ;
      //printf("i u e[st[u]].x  e[st[u]].value %d %d %d %d \n",i,u,e[st[u]].x,e[st[u]].value); 

//一开始的邻接表也很Orz啊。呜呜。。

//stu就是头结点指针(指向第一个边表节点,在插入的过程中可能不断变化),

//next是边表指针,e[I].x就是保存边表节点数据的


  }  
}
void reini()
{
  memset(e,0,sizeof(e));
  memset(st,0,sizeof(st));
  for(int i=1;i<=m;i++)
  {
      //scanf("%d%d%d",&u,&v,&w); //redirction
      e[i].x=u[i];
      e[i].value=w[i];
      e[i].next=st[v[i]];
      st[v[i]]=i;
      //printf("i e[i].next %d  %d   \n",i,e[i].next) ;  
  }      
}
int main()
{
  
scanf("%d",&test);
while(test--)
 {
      scanf("%d%d",&n,&m);
      for(int i=1;i<=m;i++)
           scanf("%d%d%d",&u[i],&v[i],&w[i]);  //一开始我只是那寻常变量来保存3个东东,囧。。。
      //memset(e,0,sizeof(e));//
      ini();
      spfa();
      long long  sum=0;
      for(int i=1;i<=n;i++)
        sum+=dis[i];
      reini();                     //来回都来一次SPFA
      spfa();
      for(int i=1;i<=n;i++)
        sum+=dis[i]; 
      printf("%lld\n",sum);  //最悲剧是这里,上面改了long long 但是,输出的时候却没改限制。囧
     
      
  }
  //system("pause");
  return 0;  
}    
    
    

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值