洛谷3385判负环模板

题目:https://www.luogu.org/problemnew/show/P3385

有DFS判负环的方法。参见《SPFA算法的优化及应用》(姜碧野)。

摘录文中一段:

  首先假设初始时存在一个点s,从该点出发我们能找到正环(即以s为起点在环上走一圈,经过任意点时的dis[x]都大于0)。下面证明对环上某个点x的重赋值不会对正环的查找产生影响。
  假设x在环上的前驱为y。本来在寻找正环时dis[y]+w(y,x)>dis[x],然后继续从x开始迭代。而如果dis[x]被重赋值了dis[x]’>=dis[y]+w(y,x),看似迭代到x时就停止了,而如果dis[x]被重赋值了dis[x]’>=dis[y]+w(y,x),看似迭代到x时就停止了,而如果dis[x]被重赋值了dis[x]’>=dis[y]+w(y,x),看似迭代到x时就停止了,也不需要再从y过渡到x。两者并无区别。依次类推,必然可以找到一个导致正环的起点。
  而开始的假设则显然成立,否则我们可以把该正环分成若干段,每段的边权和<=0,与正环的前提矛盾,由此命题得证。

其实略有点不懂。以后研究研究。

对于本题,dfs只得40分,于是用快读+spfa手写队列做到1000+ms也就能AC了。

用了一下循环队列,并觉得h!=t+1的条件挺好用的。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define ll long long
using namespace std;
const int N=4005,M=6005,INF=N<<5-5;
int T,n,m,head[N],xnt,cnt[N],q[N<<5],h,t;
ll dis[N];
bool in[N];
struct Edge{
    int next,to,w;
    Edge(int n=0,int t=0,int w=0):next(n),to(t),w(w) {}
}edge[M<<1];
int read()
{
    int ret=0;char ch;bool fx=0;
    ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')fx=1;ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        ret=ret*10+(int)ch-'0';
        ch=getchar();
    }
    return fx?-ret:ret;
}
void add(int x,int y,int z)
{
    edge[++xnt]=Edge(head[x],y,z);head[x]=xnt;
}
bool spfa()
{
    memset(dis,1,sizeof dis);memset(in,0,sizeof in);
    memset(cnt,0,sizeof cnt);h=1;t=1;
    q[1]=1;in[1]=1;dis[1]=0;
    while(h!=t+1)
    {
        int k=q[h++];in[k]=0;if(h>INF)h=1;
        for(int i=head[k],v;i;i=edge[i].next)
            if(dis[k]+edge[i].w<dis[v=edge[i].to])
            {
                dis[v]=dis[k]+edge[i].w;cnt[v]=cnt[k]+1;
                if(cnt[v]>=n)return true;
                if(!in[v])
                {
                    in[v]=1;t++;
                    if(t>INF)t=1;q[t]=v;
                }
            }
    }
    return false;
}
int main()
{
    T=read();
    while(T--)
    {
        memset(head,0,sizeof head);xnt=0;
        n=read();m=read();int x,y,z;
        for(int i=1;i<=m;i++)
        {
            x=read();y=read();z=read();add(x,y,z);
            if(z>=0)add(y,x,z);
        }
        if(spfa())printf("YE5\n");
        else printf("N0\n");
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/Narh/p/8955893.html

### 关于洛谷平台上的链式前向星模板题 在洛谷平台上,确实存在一些经典的链式前向星模板题供学习者练习。其中较为典型的题目之一是 **P3371 【模板】单源最短路径**[^2]。此题不仅涉及链式前向星的构建方法,还结合了 SPFA 或 Dijkstra 堆优化算法来求解图中的最短路径。 #### 题目描述 该题目要求处理一张带权有向图,并计算从指定起点到其他各点的最短距离。输入数据的第一行包含三个整数 N、M 和 S,分别代表点的数量、边的数量以及起始节点编号。随后 M 行每行给出一条边的信息,包括两个端点及其权重。 为了高效存储稀疏图结构并支持快速访问邻接表,在实现过程中通常采用链式前向星作为底层的数据结构[^1]。 以下是基于 C++ 的简单代码框架用于演示如何利用链式前向星配合优先队列完成上述任务: ```cpp #include <bits/stdc++.h> using namespace std; const int MAXN = 1e5 + 5; struct Edge { int to, next, w; // 终点,下一条边的位置索引,边权值 } edge[MAXN << 1]; int head[MAXN], tot; long long dist[MAXN]; bool vis[MAXN]; void add_edge(int u, int v, int w){ edge[++tot].to = v; edge[tot].w = w; edge[tot].next = head[u]; head[u] = tot; } priority_queue<pair<long long,int>,vector<pair<long long,int>>,greater<>> pq; void dijkstra(int s){ memset(dist,0x3f,sizeof dist); dist[s]=0;pq.emplace(0,s); while(!pq.empty()){ auto [d,u]=pq.top();pq.pop(); if(vis[u]) continue; vis[u]=true; for(int i=head[u];i;i=edge[i].next){ int v=edge[i].to,w=edge[i].w; if(dist[v]>dist[u]+w){ dist[v]=dist[u]+w; pq.emplace(dist[v],v); } } } } ``` 以上程序片段展示了如何通过链式前向星建立图模型,并借助最小堆加速版Dijkstra算法解决问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值