poj3259

题目大意是,F个农场,N点,m条无向边以及每两个连接的点要花费的时间,w条有向边,从一点到另一点可减少一定时间,问是否有可能问你从某个点开始走,能回到从前。

两种解法

spfa

#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<set>
using namespace std;
//spfa
int head[605],d[605];
bool vis[605];
int use[605];
int n,m,w;
struct edge
{
    int u,v,t;
    int next;
}e[6000];

bool spfa()
{
    for(int i=0;i<=n;i++)
    {
        d[i]=INF;
        vis[i]=0;
        use[i]=0;
    }//初始化
    queue<int>q;
//任取第一边的第一点存入
    q.push(e[1].u);
    vis[e[1].u]=1;
    d[e[1].u]=0;
    ++use[e[1].u];//表示该点已经过一次
    while(!q.empty())
    {
        int temp=q.front();
        q.pop();
        vis[temp]=0;
        for(int i=head[temp];i!=-1;i=e[i].next)
        {
            if(d[e[i].v]>d[e[i].u]+e[i].t)
            {
                d[e[i].v]=d[e[i].u]+e[i].t;
                if(!vis[e[i].v])
                {
                    q.push(e[i].v);
                    if(++use[e[i].v]>=n)return 1;//入队次数超过总数,则存在回路
                    vis[e[i].v]=1;
                }
            }
        }
    }
    return 0;
}
int main()
{
    int f;
    cin>>f;
    while(f--)
    {
    cin>>n>>m>>w;
    memset(head,-1,sizeof(head));
    for(int i=1;i<=2*m;i+=2)
    {
        cin>>e[i].u>>e[i].v>>e[i].t;
        e[i+1].v=e[i].u;
        e[i+1].u=e[i].v;
        e[i+1].t=e[i].t;
        e[i].next=head[e[i].u];
        head[e[i].u]=i;
        e[i+1].next=head[e[i+1].u];
        head[e[i+1].u]=i+1;
    }
    for(int i=2*m+1;i<=2*m+w;i++)
    {
        cin>>e[i].u>>e[i].v>>e[i].t;
        e[i].t=-e[i].t;
        e[i].next=head[e[i].u];
        head[e[i].u]=i;
    }
    if(spfa())cout<<"YES"<<endl;
    else cout<<"NO"<<endl;
    }
    return 0;
}
bellmanford

#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<set>
#define INF (1<<26)
using namespace std;
//bellman_ford
struct edge
{
    int u,v,t;
}e[6000];
int n,m,w;
int dis[1005];
int bellman_ford()
{
  for(int i=0;i<=n;i++)dis[i]=INF;
  dis[1]=0;
  for(int i=0;i<n-1;i++)
  {
  for(int j=0;j<2*m+w;j++)
  {
      int a=e[j].u;
      int b=e[j].v;
      int s=e[j].t;
     if(dis[b]>dis[a]+s&&dis[a]<INF)dis[b]=dis[a]+s;//dis[a]必须<inf
  }
  }
  for(int i=0;i<2*m+w;i++)
  {
      int a=e[i].u;
      int b=e[i].v;
      int s=e[i].t;
     if(dis[b]>dis[a]+s&&dis[a]<INF)return 1;
  }//重新遍历一次,看是否存在负权回路
  return 0;
}
int main()
{
    int f;
    cin>>f;
    while(f--)
    {
        cin>>n>>m>>w;
        for(int i=0;i<2*m;i+=2)
        {
            cin>>e[i].u>>e[i].v>>e[i].t;
            e[i+1].v=e[i].u;
            e[i+1].u=e[i].v;
            e[i+1].t=e[i].t;
        }
        int cnt=2*m;
        for(int i=0;i<w;i++)
        {
            cin>>e[cnt+i].u>>e[cnt+i].v>>e[cnt+i].t;
            e[cnt+i].t=-e[cnt+i].t;
        }
        if(bellman_ford())cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值