洛谷P1993 小K的农场——差分约束系统。spfa+queue,或spfa+deque,或dfs_spfa

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

如果a==b,则等价于a-b>=0,b-a>=0

本题给出三种解法。

一是bfs_spfa+单端队列;二是dfs_spfa;三是bfs_spfa+双端队列

解法一:bfs_spfa+单端队列。4106ms,耗时较长。第6、10个点都超过1000ms

判断正环,有两个方法:

一)最长链长度超过n

二)某个点松驰次数超过n

解法二:dfs_spfa。48ms

通过递归深度可以很方便地判断有没有正环。

关键代码如下:

void dfs_spfa(int from){
	if(flg)return;
	in_stack[from]=true;//染色 
	for(int i=head[from];i;i=edge[i].nxt){
		int to=edge[i].to;
        int w=edge[i].w;
        if(dis[to]<dis[from]+w){//取大
        	dis[to]=dis[from]+w;
            if(in_stack[to]) {
				flg=1;//已在染色栈中,说明有正环
				return;
			}
			else dfs_spfa(to);
		} 
	}
	in_stack[from]=false;//回溯 
}

解法三:bfs_spfa+双端队列。1503ms

利用STL自带的双端队列deque,函数如下:

push_front(x):双端队列头部增加一个元素X

push_back(x):双端队列尾部增加一个元素x

pop_front():删除双端队列中最前一个元素

pop_back():删除双端队列中最后一个元素

front():返回首元素的引用

back():返回尾元素的引用

empty():若空,则返回true;否则返回true

因为是求最长路,所以将dis大的点压入队列尾部,小的压入队列头部。

关键代码如下:

 

AC代码一:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
const int Maxn=1e4+5;
int n,m;
int num,head[Maxn];
int hd=0,tl=1,que[4*Maxn],vis[Maxn];//que,非循环队列时,如果开2000*Maxn,才出正确答案 
int dis[Maxn],tot[Maxn];
struct Edge{
    int to,nxt,w;
}edge[4*Maxn];
void join(int from,int to,int w){
    edge[++num].nxt=head[from];
    edge[num].to=to;
    edge[num].w=w;
    head[from]=num;
}
bool spfa(int st){ 
    for(int i=0;i<=n;i++)dis[i]=-1e9;	
    hd=0;
    tl=1;
    que[1]=st;
    dis[st]=0;
    tot[st]=1;
    vis[st]=1;
    while(hd!=tl){
    	hd=hd%20007+1;
        int from=que[hd];
        vis[from]=0;
        for(int i=head[from];i;i=edge[i].nxt){
            int to=edge[i].to;
            int w=edge[i].w;
            if(dis[to]<dis[from]+w){//取大 
                dis[to]=dis[from]+w;
                tot[to]=tot[from]+1;
                //cout<<tot[to]<<' ';
                if(tot[to]>n)return 1;//判断有没有正权回路 
                if(!vis[to]){
                	tl=tl%20007+1;
                    que[tl]=to;
                    vis[to]=1;
                }
            }
        }   
    }
    return 0;   
}
int main(){
    //freopen("testdata3.in","r",stdin);
    cin>>n>>m;
    int id,a,b,c;
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&id,&a,&b);
        if(id==1){
        	scanf("%d",&c);
        	join(b,a,c);//ai-bi>=ci
        }
        if(id==2){
        	scanf("%d",&c);
        	join(a,b,-c);//ai-bi<=ci,bi-ai>=-ci 
        }
        if(id==3){
        	join(a,b,0);
        	join(b,a,0);
        }
    }
    for(int i=1;i<=n;i++)
        join(0,i,0);//虚拟点0
    if(spfa(0)){
        printf("%s","No");
    }
    else printf("%s","Yes");
    return 0;
}

AC代码二:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
const int Maxn=1e4+5;
int n,m;
int num,head[Maxn];
bool in_stack[10*Maxn],flg;
int dis[Maxn];
struct Edge{
    int to,nxt,w;
}edge[10*Maxn];
void join(int from,int to,int w){
    edge[++num].nxt=head[from];
    edge[num].to=to;
    edge[num].w=w;
    head[from]=num;
}
void dfs_spfa(int from){
	if(flg)return;
	in_stack[from]=true;//染色 
	for(int i=head[from];i;i=edge[i].nxt){
		int to=edge[i].to;
        int w=edge[i].w;
        if(dis[to]<dis[from]+w){//取大
        	dis[to]=dis[from]+w;
            if(in_stack[to]) {
				flg=1;//已在栈中,说明有正环
				return;
			}
			else dfs_spfa(to);
		} 
	}
	in_stack[from]=false;//回溯 
}
int main(){
    cin>>n>>m;
    int id,a,b,c;
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&id,&a,&b);
        if(id==1){
        	scanf("%d",&c);
        	join(b,a,c);//ai-bi>=ci
        }
        if(id==2){
        	scanf("%d",&c);
        	join(a,b,-c);//ai-bi<=ci,bi-ai>=-ci 
        }
        if(id==3){
        	join(a,b,0);
        	join(b,a,0);
        }
    }
    for(int i=1;i<=n;i++)
        join(0,i,0);//虚拟点0
    
    for(int i=0;i<=n;i++)dis[i]=-1e9;
    dis[0]=0;
    dfs_spfa(0);
	if(flg){
        printf("%s","No");
    }
    else printf("%s","Yes");
    return 0;
}

AC代码三:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<deque>
using namespace std;
const int Maxn=1e4+5;
int n,m;
int num,head[Maxn];
int vis[Maxn],dis[Maxn],tot[Maxn];
deque<int> q;
struct Edge{
    int to,nxt,w;
}edge[4*Maxn];
void join(int from,int to,int w){
    edge[++num].nxt=head[from];
    edge[num].to=to;
    edge[num].w=w;
    head[from]=num;
}
bool spfa(int st){ 
	for(int i=0;i<=n;i++)dis[i]=-1e9;	
	q.push_front(st);
    dis[st]=0;
    tot[st]=1;
    vis[st]=1;
    while(!q.empty()){
        int from=q.front();
        q.pop_front();
        vis[from]=0;
        for(int i=head[from];i;i=edge[i].nxt){
            int to=edge[i].to;
            int w=edge[i].w;
            if(dis[to]<dis[from]+w){//取大 
                dis[to]=dis[from]+w;
                tot[to]=tot[from]+1;
                if(tot[to]>n)return 1;//判断有没有正权回路 
                if(!vis[to]){
                	if(!q.empty() && dis[to]>dis[q.front()])
                		q.push_back(to);
                	else q.push_front(to);
                    vis[to]=1;
                }
            }
        }   
    }
    return 0;   
}
int main(){
    cin>>n>>m;
    int id,a,b,c;
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&id,&a,&b);
        if(id==1){
        	scanf("%d",&c);
        	join(b,a,c);//ai-bi>=ci
        }
        if(id==2){
        	scanf("%d",&c);
        	join(a,b,-c);//ai-bi<=ci,bi-ai>=-ci 
        }
        if(id==3){
        	join(a,b,0);
        	join(b,a,0);
        }
    }
	for(int i=1;i<=n;i++)
		join(0,i,0);//虚拟点0
	if(spfa(0)){
		printf("%s","No");
	}
    else printf("%s","Yes");
    return 0;
}

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值