POJ 3259 Wormholes(再续前章)

题目大意:bellman-ford模板题

思路:以前是对着模板敲,时隔一年,自己温习了一边算法自己敲出来的,因为一个宏定义WA到想哭,至今没想清楚是什么意思.但终究是码出来了

算法核心思想就是:

第一重循环: 松弛n-1遍

第二重循环: 扫描所有的边,每次松弛一下入度结点

 

松弛了n-1遍之后,肯定能求得最短距离了

这时候如果再对所有的边再松弛一遍,如果还能够松弛话,则有负环

否则没有

O(n*m)的效率

 

AC  Program:

#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
typedef long long ll;
#define	clr(a)		memset((a),0,sizeof (a))
#define	rep(i,a,b)	for(int i=(a);i<(int)(b);i++)
#define	per(i,a,b)	for(int i=((a)-1);i>=(int)(b);i--)
#define	inf	0x7ffffff
#define	eps			1e-6
using namespace std;
int n,m,who;
int head[1510];
int dis[1510];
int cnt;//总边数
struct edge{
 int from,to,w,next;       
}e[5500]; 
void init(){
    cnt=0; 
    int u,v,wei;
    memset(e,0,sizeof(e));//初始化边数组 
    memset(head,-1,sizeof(head));//一开始初始化为0了,嚓 
    for(int i=0;i<m;i++){
        scanf("%d%d%d",&u,&v,&wei);
        e[cnt].from=u;
        e[cnt].to=v;
        e[cnt].w=wei;
        e[cnt].next=head[u];
        head[u]=cnt++;
        
        e[cnt].from=v;
        e[cnt].to=u;
        e[cnt].w=wei;
        e[cnt].next=head[v];
        head[v]=cnt++;    
    }     
    for(int i=0;i<who;i++){
       scanf("%d%d%d",&u,&v,&wei);
       wei=-1*wei;
       
       e[cnt].from=u;
       e[cnt].to=v;
       e[cnt].w=wei;
       e[cnt].next=head[u];
       head[u]=cnt++; 
       
    }
}
bool bellman_ford(){
     //初始化相关数组?
     //直接松弛?
     for(int i=1;i<=n;i++){
        dis[i]=inf;     
     }
     
     dis[1]=0;
     for(int i=0;i<n-1;i++){
         for(int j=1;j<=n;j++){ //其实这里直接枚举所有的边也是可以的,不需要利用顶点来带出出边 
            //if(dis[j]==inf)continue; //小剪枝 
            for(int k=head[j];k!=-1;k=e[k].next){
                int tt=e[k].to; //出边点 
                if(dis[tt]>dis[j]+e[k].w){//加e[k].w 小剪枝
                    dis[tt]=dis[j]+e[k].w;                          
                }       
                
            }      
         }        
     }
     for(int j=1;j<=n;j++){
       //if(dis[j]==inf)continue;      
       for(int k=head[j];k!=-1;k=e[k].next){
          int tt=e[k].to;

          if(dis[tt]>dis[j]+e[k].w){//如果dis[tt]=inf,就说明没更新过,说明有可能是无法到达的点
                                  //但有一点可以肯定,那就是没有松弛过,这样的点肯定不会存在于负环当中        
              return 1;//存在负环 
          }
       }        
     }      
     return 0;//不存在负环 
} 
int main(){
  int test;
  cin>>test;
  while(test--){
     scanf("%d%d%d",&n,&m,&who);
     //输入
     //调用算法
     init();            
     if(bellman_ford())
        printf("YES\n");
     else
        printf("NO\n"); 
       
  };  
  //system("pause");
  return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值