CSU1978-LXX的图论题-SPFA判环

CSU1978-LXX的图论题-SPFA判环

Description

由于lxx的图论和数据结构太弱了,大佬Z决定为lxx补一补。于是大佬Z为lxx出了一道题目,题目如下:给出一张有向图,图中有n个点,m条边,每条边上都有一个权值w,问图中是否存在满足以下条件的点i,j,…p使得不等式w[i][j] * w[j][k] * …. * w[p][i]<1成立。奈何lxx太弱了,他决定寻求你的帮助。

Input

多组输入,以文件结尾。第一行两个整数n( 1<=n<=500 ),m( 1<=m<=n*(n-1)/2 ),接下来m行,每行3个数x,y,z,(x≠y):表示x到y有一条边,权值为z(0

Output

如果存在满足题目所描述的式子,输出“YES”,否则输出“NO”。

Sample Input

2 2
1 2 0.9
2 1 1.2
6 4
1 2 0.1
2 4 0.8
4 1 12
4 1 15

Sample Output

NO
YES

Hint

点的编号为1~n


思路

就是SPFA判环嘛

首先把式子取个对数从乘法变成加法,于是就是裸的判负环了

但是我比赛的时候没A,不知道乘法会精度丢失,毕竟500个……

AC代码

/**************************************
 *Source            : CSU1978
 *Knowledge Point   : SPFA_PENDING_CYCLE
 *Author            : CSUzick
**************************************/
#include <cstdio>
#include <iomanip>
#include <cstring>
#include <iostream>
#include <stack>
#include <vector>
#include <queue>
#include <cctype>
#include <cmath>
#include <algorithm>
#include <set>
#include <bitset>
#include <map>
#define LL long long
#define mk(a,b) make_pair(a,b)
#define ULL unsigned long long
#define mem(a,n) memset(a,n,sizeof(a))
#define fread freopen("in.txt","r",stdin)
#define fwrite freopen("out.txt","w",stdout)
#define N 550
#define INF 0x3f3f3f3f
#define eps 1e-12
using namespace std;
struct Edge{
    int from,to;
    double dist;
    Edge(int u,int v,double d):from(u),to(v),dist(d){};
};
struct SPFA{
    vector<Edge> edges;
    vector<int> G[N];
    bool inque[N];
    double d[N];
    int cnt[N];
    int n,m;

    void init(int n){
        this->n=n;
        for(int i=0;i<=n;++i){
            G[i].clear();
        }
        edges.clear();
    }

    void AddEdge(int from,int to,double dist){
        edges.push_back(Edge(from,to,dist));
        m=edges.size();
        G[from].push_back(m-1);
    }

    bool spfa(){
        queue<int> que;
        memset(inque,0,sizeof(inque));
        memset(cnt,0,sizeof(cnt));
        for(int i=0;i<=n;++i){
            que.push(i); 
            d[i]=0;
            inque[i]=false;
        }
        while(!que.empty()){
            int temp=que.front();
            if(cnt[temp]==n){
                return true;
            }
            que.pop();
            inque[temp]=false;
            for(int i=0;i<G[temp].size();++i){
                Edge &e=edges[G[temp][i]];
                if(d[e.to]-d[temp]-e.dist>eps){
                    d[e.to]=d[temp]+e.dist;
                    if(!inque[e.to]){
                        que.push(e.to);
                        inque[e.to]=true;
                        if(++cnt[e.to]>=n)  return true;
                    }
                }
            }
        }
        return false;
    }
};
SPFA SMF;
int main()
{
    int n,m,u,v;
    double c;
    while(~scanf("%d%d",&n,&m)){
        SMF.init(n);
        while(m--){
            scanf("%d%d%lf",&u,&v,&c);
            SMF.AddEdge(u,v,log2(c));
        }
        if(SMF.spfa()){
            printf("YES\n");
        }else{
            printf("NO\n");
        }
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值