【S - Layout】

80 篇文章 0 订阅
80 篇文章 0 订阅

算法:SPFA+SLF

思路:

  • 差分约束,详见AndyZhang的BLOG。注意是可以直接建造负权路径的。
  • 发现负环,则是无解;dis[N]==INF,则是无穷解;有唯一解(本题中为最短路)输出 dis[N]
  • 终于成功用SLF优化了SPFA!降低到了16ms
  • 而且:LLL根本不优化,反而会降速到63ms

代码:

  • 朴素SPFA:47ms 828kB
//47ms		828kB


#include <iostream>
#include <queue>
#include <cstring>
#include <cstdio>
#define INF 0x3f3f3f3f

using namespace std;

const int maxn = 1005;

int N,ML,MD;
int dis[maxn];
struct EDGE{
	int to;
	int w;
	int fo;
}E[maxn * 20] ;int cnt=0;
int tail[maxn];
void ADDEDGE(int u,int v,int w){
	++cnt;
	E[cnt].to = v;
	E[cnt].w = w;
	E[cnt].fo = tail[u];
	tail[u] = cnt;
	return ;
}

queue<int> q;
int rec[maxn];//record
bool enq[maxn];//enqueue
int SPFA(){
	memset(dis,INF,sizeof(dis));
	memset(rec, 0 ,sizeof(rec));
	memset(enq, 0 ,sizeof(enq));
	q.push(1);dis[1]=0;enq[1]=true;rec[1]=1;
	while(q.size()){
		int cur = q.front() ; q.pop() ; enq[cur] = false;
		for(int i=tail[cur] ; ~i ; i=E[i].fo){
			int v = E[i].to;
			if(dis[v] > dis[cur] + E[i].w){
				dis[v] = dis[cur] + E[i].w;
				if(!enq[v]){
					q.push(v);
					rec[v]++;
					enq[v] = true;
					if(rec[v] == N)
						return -1;//有负环 
				}
			}
		}
	}
	return dis[N] == INF ? -2 : dis[N] ;
}

int main(){
	scanf("%d%d%d",&N,&ML,&MD);
	memset(tail , -1 , sizeof(tail));
	while(ML--){
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		ADDEDGE(u,v,w);
	}
	while(MD--){
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		ADDEDGE(v,u,-w);
	}
	printf("%d\n",SPFA());
	return 0;
}
  • SPFA+SLF:16ms 836kB
//16ms		836kB


#include <iostream>
#include <queue>
#include <cstring>
#include <cstdio>
#define INF 0x3f3f3f3f

using namespace std;

const int maxn = 1005;

int N,ML,MD;
int dis[maxn];
struct EDGE{
	int to;
	int w;
	int fo;
}E[maxn * 20] ;int cnt=0;
int tail[maxn];
void ADDEDGE(int u,int v,int w){
	++cnt;
	E[cnt].to = v;
	E[cnt].w = w;
	E[cnt].fo = tail[u];
	tail[u] = cnt;
	return ;
}

deque<int> q;//SLF
int rec[maxn];//record
bool enq[maxn];//enqueue
int SPFA(){
	memset(dis,INF,sizeof(dis));
	memset(rec, 0 ,sizeof(rec));
	memset(enq, 0 ,sizeof(enq));
	q.push_front(1);dis[1]=0;enq[1]=true;rec[1]=1;
	while(q.size()){
		int cur = q.front() ; q.pop_front() ; enq[cur] = false;
		for(int i=tail[cur] ; ~i ; i=E[i].fo){
			int v = E[i].to;
			if(dis[v] > dis[cur] + E[i].w){
				dis[v] = dis[cur] + E[i].w;
				if(!enq[v]){
					if(q.size() && dis[v] > dis[q.front()])//SLF
						q.push_back(v);
					else
						q.push_front(v);
					rec[v]++;
					enq[v] = true;
					if(rec[v] == N)
						return -1;//有负环 
				}
			}
		}
	}
	return dis[N] == INF ? -2 : dis[N] ;
}

int main(){
	scanf("%d%d%d",&N,&ML,&MD);
	memset(tail , -1 , sizeof(tail));
	while(ML--){
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		ADDEDGE(u,v,w);
	}
	while(MD--){
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		ADDEDGE(v,u,-w);
	}
	printf("%d\n",SPFA());
	return 0;
}
  • SPFA+LLL:63ms 836kB
//63ms		836kB


#include <iostream>
#include <queue>
#include <cstring>
#include <cstdio>
#define INF 0x3f3f3f3f

using namespace std;

const int maxn = 1005;

int N,ML,MD;
int dis[maxn];
struct EDGE{
	int to;
	int w;
	int fo;
}E[maxn * 20] ;int cnt=0;
int tail[maxn];
void ADDEDGE(int u,int v,int w){
	++cnt;
	E[cnt].to = v;
	E[cnt].w = w;
	E[cnt].fo = tail[u];
	tail[u] = cnt;
	return ;
}

deque<int> q;//SLF
int rec[maxn];//record
bool enq[maxn];//enqueue
int SPFA(){
	int sum=0;//LLL
	int num  ;//LLL
	memset(dis,INF,sizeof(dis));
	memset(rec, 0 ,sizeof(rec));
	memset(enq, 0 ,sizeof(enq));
	q.push_front(1);dis[1]=0;enq[1]=true;rec[1]=1; 
	while(num = q.size()){
		int cur = q.front() ; q.pop_front();
		while(dis[cur] * num > sum){
			q.push_back(cur);
			cur = q.front() ; q.pop_front() ;
		}
		sum -= dis[cur];enq[cur]=false;//LLL
		for(int i=tail[cur] ; ~i ; i=E[i].fo){
			int v = E[i].to;
			if(dis[v] > dis[cur] + E[i].w){
				dis[v] = dis[cur] + E[i].w;
				if(!enq[v]){
					q.push_front(v);
					sum += dis[v];//LLL
					rec[v]++;
					enq[v] = true;
					if(rec[v] == N)
						return -1;//有负环 
				}
			}
		}
	}
	return dis[N] == INF ? -2 : dis[N] ;
}

int main(){
	scanf("%d%d%d",&N,&ML,&MD);
	memset(tail , -1 , sizeof(tail));
	while(ML--){
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		ADDEDGE(u,v,w);
	}
	while(MD--){
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		ADDEDGE(v,u,-w);
	}
	printf("%d\n",SPFA());
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值