poj 3259 最短路(带负环)

题目的意思是:给出农场的路线图, 并且存在风洞(经过风洞所需的时间为负的) , 问你从一个农场出发,经常其他路线和风洞 ,能不能存在一条路线,使你返回到原点的时候,所花的时间为负的,

也就是问你所给的图中是否存在负权环。

注意:1、本题中存在重边的数据。

 

本题有三中解法 1、mellman_ford 2、SPFA 3、深搜或则宽搜  

 这里只给出解法1和2的代码:

 

1:

#include
using namespace std;

const int inf = 100100 ;
int t ;
int farm1[10010] , farm2[10010] ;
int w[10010];
int dist[520] ;

int main()
{
 
cin>>t;
 
while(t--)
 
{
 
 int n , m , w1 , i ,j =0;
 
 cin>>n>>m>>w1;
 
 int x = 0, y = 0, sum;
 
 for(i = 0 ; i < m;i++)
 
 {
 
  cin>>x>>y>>sum;
 
  farm1[j] = x; farm2[j] = y;
 
  w[j] = sum; 
 
  j += 1;
 
  farm2[j] = x; farm1[j] = y;
 
  w[j] = sum; 
 
  j += 1;
 
 }
 
 for(i = 0 ; i < w1;i++)
 
 {
 
  cin>>x>>y;
 
  cin>>sum;
 
  farm1[j] = x; farm2[j] = y;//cout<<x<<y<<endl;
 
  w[j] = -sum ;j+=1;
 
 }
 
 for(i =1 ; i <= n ;i++)
 
  dist[i] =inf;
 
 dist[1] = 0 ;
 
 for(int k = 1 ; k < n;k++)
 
 {
 
  for(i = 0 ; i< j; i++)
 
  {
 
   x= farm1[i] ; y = farm2[i];
 
   if(dist[y]> (dist[x]+w[i]))   dist[y] =dist[x]+w[i];
 
  }
 
 }
// 
 for(i= 1; i <=n;i++)
// 
  cout<<dist[i]<<endl;
 
 int d = 0 ;
 
 for(i = 0 ; i < j ;i++)
 
  {
 
   x= farm1[i] ; y = farm2[i];
 
   if(dist[y]> (dist[x]+w[i]))  { d = 1 ;break;}
 
  }
 
 if(d)cout<<"YES"<<endl;
 
 elsecout<<"NO"<<endl;
 
}
 
return 0;
  //时间266ms

 

 

2、SPFA

#include
#include
#include
using namespace std;

int farm[520][520] , dis[520] , vst[520] ;
int n , m , w;

int main()
{
 
int t ;
 
cin>>t;
 
while(t--)
 
{
 
 cin>>n>>m>>w;
 
 int i  , x , y, sum ;
 
 memset(farm , 0 ,sizeof(farm));
 
 for(i = 0 ; i < m;i++)
 
 {
 
  cin>>x>>y>>sum;
 
  if(farm[x][y]!= 0)  
 
  {
 
   if(farm[x][y]> sum)   {farm[x][y] = sum ; farm[y][x] = sum ;}
 
  }
 
  else
 
  {
 
   farm[x][y]= sum ; farm[y][x] = sum ;
 
  }
 
 }
 
 for(i = 0 ; i < w ;i++)
 
 {
 
  cin>>x>>y>>sum;
 
  if(farm[x][y]!= 0)  
 
  {
 
   if(farm[x][y]> -sum)   farm[x][y] = -sum ;
 
  }
 
  else
 
   farm[x][y]= -sum ;
 
  
 
 }
 
 for(i = 1 ; i<= n ;i++)
 
  dis[i] =100100 ;
 
 dis[1] = 0;
 
 

  memset(vst , 0 ,sizeof(vst));
 
 vst[1] = 1;
 
 int bz[520];
 
 stack q;
 
 q.push(1);
 
 memset(bz , 0,sizeof(bz));
 
 bz[1]+= 1;
 
 int pri = 0 , end= 1 , d =0;


 
 while(!q.empty())
 
 {
 
  int p =q.top() ;  q.pop();
 
  for(i = 1 ; i<= n ; i++)
 
  {
 
   if(farm[p][i]&& (dis[p]+farm[p][i]) < dis[i] )
 
   {
 
    dis[i]= dis[p]+farm[p][i] ;
 
    if(!vst[i])
 
    {
 
     q.push(i);
 
     vst[i]= 1;
 
     bz[i]+= 1;
 
     if(bz[i]> n)  {d = 1 ;  break;}
 
    }
 
   }
 
  }
 
  if(d == 1)  break;
 
  vst[p] = 0;
 
  pri+=1;
 
 
 
 }
 
 //int d = 0;
 
 // for(i = 1 ;i <= n;  i++)
 
 //  if(bz[i]> n)  {d = 1 ; break;}
 
 
 
 if(d)  cout<<"YES"<<endl;
 
 else cout<<"NO"<<endl;
 
}
 
return 0;
} //时间786ms

 

 

1、其实这个题目的测试数据很弱( 对于取源点 ), 本题中任去一个点都行。 

2、本来spfa的速度是要比mellman_ford快的, 在这里去spfa用了700多ms ,可能是没有优化好的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值