图论--单源最短路


因为以前太懒,所以前没发什么博客。今天本人第一天写博客吧,hh
因为本人擅长图论就从图论开始吧。
说到图论,不得不提最短路问题。
简单看看最短路吧hh

dijkstra(优先队列优化)

void dijkstra(int s)
{
	memset(d,0x7f,sizeof(d));
	memset(v,0,sizeof(v));
	d[s]=0;
	q.push(make_pair(0,s));
	while(q.size())
	{
		int x=q.top().second;
		q.pop();
		if(v[x])  continue;
		v[x]=1;
		for(int i=head[x];i;i=next[i])
		{
			int y=ver[i],z=edge[i];
			if(d[y]>d[x]+z)
			{
				d[y]=d[x]+z;
				q.push(make_pair(-d[y],y));
			}
		}
	}
}

spfa(bfs版)

void spfa()
{
	memset(d,0x3f,sizeof(d));
	d[u]=1;
	visit[u]=1;
	q.push(u);
	while(q.size())
	{
		int x=q.front();
		q.pop();
		visit[x]=0;
		for(int i=0;i<b[x].size();i++)
		{
			int y=b[x][i];
			double z=a[x][y];
			if(d[y]<d[x]*z)
			{
				d[y]=d[x]*z;
				if(!visit[y])  q.push(y),visit[y]=1;
			}
		}
		visit[x]=1;
	}
}

spfa(dfs版,没听说过吧)

void spfa(int x)
{
	if(flag)  return;
	v[x]=1;
	for(int i=head[x];i;i=e[i].next)
	{
		int y=e[i].ver;
		double z=e[i].dis;
		if(d[y]>d[x]+z)
		{
			d[y]=d[x]+z;
			if(!v[y])  spfa(y);
			else
			{
				flag=1;
				return;
			}
		}
	}
	v[x]=0;
}

这里特别提一下,为什么要会深搜的spfa
以下题为例:

洛谷P1768

[link] (https://www.luogu.com.cn/problem/P1768)
题目描述
“那是一条神奇的天路诶~~~,把第一个神犇送上天堂~~~”,XDM先生唱着这首“亲切”的歌曲,一道猥琐题目的灵感在脑中出现了。

和C_SUNSHINE大神商量后,这道猥琐的题目终于出现在本次试题上了,旨在难到一帮大脑不够灵活的OIer们(JOHNKRAM真的不是说你……)。

言归正传,小X的梦中,他在西藏开了一家大型旅游公司,现在,他要为西藏的各个景点设计一组铁路线。但是,小X发现,来旅游的游客都很挑剔,他们乘火车在各个景点间游览,景点的趣味当然是不用说啦,关键是路上。试想,若是乘火车一圈转悠,却发现回到了游玩过的某个景点,花了一大堆钱却在路上看不到好的风景,那是有多么的恼火啊。

所以,小X为所有的路径定义了两个值,Vi和Pi,分别表示火车线路的风景趣味度和乘坐一次的价格。现在小X想知道,乘客从任意一个景点开始坐火车走过的一条回路上所有的V之和与P之和的比值的最大值。以便为顾客们推荐一条环绕旅游路线(路线不一定包含所有的景点,但是不可以存在重复的火车路线)。

于是,小X梦醒之后找到了你……

输入格式
第一行两个正整数N,M,表示有N个景点,M条火车路线,火车路线是单向的。

以下M行,每行4个正整数,分别表示一条路线的起点,终点,V值和P值。

注意,两个顶点间可能有多条轨道,但一次只能走其中的一条。

输出格式
一个实数,表示一条回路上最大的比值,保留1位小数。

若没有回路,输出-1。

输入输出样例
输入 #1复制
5 6
1 2 1 1
4 1 6 2
5 4 8 1
2 3 2 2
5 2 4 1
3 5 6 4
输出 #1复制
2.3
说明/提示
对于30%的数据,1≤N≤100,1≤M≤20;

对于60%的数据,1≤N≤3,000,1≤M≤2,000;

对于100%的数据,1≤N≤7,000,1≤M≤20,000,1≤Vi,Pi≤1,000.

保证答案在200以内.

首先,这道题有负环,因此不能用dijkstra。
在最开始的时候,我就交了一个简单的SPFA上去,果不其然,它死了。

#include <bits/stdc++.h>
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#define inf 0x7fffffff
#define ll long long
//#define int long long
//#define double long double
#define eps 1e-5
//#define mod 1e9+7
using namespace std;
const int mod=1e9;
const int N=4e4+5;
int n,m;
struct node
{
	int ver,next;
	double edge1,edge2,dis;
}e[N];
double l,r=200;
int head[N],tot;
double d[N];
int v[N],cnt[N];
bool flag;
void add(int x,int y,double v,double p)
{
	e[++tot].ver=y;
	e[tot].edge1=v;
	e[tot].edge2=p;
	e[tot].next=head[x];
	head[x]=tot;
}
bool spfa(int s)
{
	for(int i=1;i<=n;i++)
	{
		v[i]=0;
		d[i]=1e9;
		cnt[i]=0;
	}
	d[s]=0; 
	v[s]=1;
	queue < int > q;
	q.push(s);
	while(q.size())
	{
		int x=q.front();
		q.pop();
		if(cnt[x]>20)  return true;
		v[x]=0;
		for(int i=head[x];i;i=e[i].next)
		{
			int y=e[i].ver;
			double z=e[i].dis;
			if(d[y]>d[x]+z)
			{
				cnt[y]++;
				d[y]=d[x]+z;
				if(cnt[y]>20)  return true;
				if(!v[y])
				{
					v[y]=1;
					q.push(y);
				}
			}
		}
	}
	return false;
}
signed main()
{
//	ios::sync_with_stdio(false);
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
    	int x,y;
		double v,p;
    	scanf("%d%d%lf%lf",&x,&y,&v,&p);
    	add(x,y,v,p);
    }
    while(r-l>=1e-2)
    {
    	double mid=(r+l)/2;
    	flag=0;
    	for(int i=1;i<=tot;i++)  e[i].dis=e[i].edge2*mid-e[i].edge1;
    	for(int i=1;i<=n;i++)
    	{
    		flag=spfa(1) || spfa(n) || spfa(n >> 1);
    		if(flag)  break;
    	}
    	if(flag)  l=mid;
    	else r=mid;
    }
    if(l==0)  cout<<"-1";
    else printf("%.1lf",r);
    return 0;
}

在这里插入图片描述

剪枝+O2:

#include <bits/stdc++.h>
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#define inf 0x7fffffff
#define ll long long
//#define int long long
//#define double long double
#define eps 1e-5
//#define mod 1e9+7
using namespace std;
const int mod=1e9;
const int N=4e4+5;
int n,m;
struct node
{
	int ver,next;
	double edge1,edge2,dis;
}e[N];
double l,r=200;
int head[N],tot;
double d[N];
int v[N],cnt[N];
bool flag;
void add(int x,int y,double v,double p)
{
	e[++tot].ver=y;
	e[tot].edge1=v;
	e[tot].edge2=p;
	e[tot].next=head[x];
	head[x]=tot;
}
bool spfa(int s)
{
	for(int i=1;i<=n;i++)
	{
		v[i]=0;
		d[i]=1e9;
		cnt[i]=0;
	}
	d[s]=0; 
	v[s]=1;
	queue < int > q;
	q.push(s);
	while(q.size())
	{
		int x=q.front();
		q.pop();
		if(cnt[x]>20)  return true;
		v[x]=0;
		for(int i=head[x];i;i=e[i].next)
		{
			int y=e[i].ver;
			double z=e[i].dis;
			if(d[y]>d[x]+z)
			{
				cnt[y]++;
				d[y]=d[x]+z;
				if(cnt[y]>20)  return true;
				if(!v[y])
				{
					v[y]=1;
					q.push(y);
				}
			}
		}
	}
	return false;
}
signed main()
{
//	ios::sync_with_stdio(false);
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
    	int x,y;
		double v,p;
    	scanf("%d%d%lf%lf",&x,&y,&v,&p);
    	add(x,y,v,p);
    }
    while(r-l>=1e-2)
    {
    	double mid=(r+l)/2;
    	flag=0;
    	for(int i=1;i<=tot;i++)  e[i].dis=e[i].edge2*mid-e[i].edge1;
    	flag=spfa(1) || spfa(n) || spfa(n >> 1);
    	if(flag)  l=mid;
    	else r=mid;
    }
    if(l==0)  cout<<"-1";
    else printf("%.1lf",r);
    return 0;
}

在这里插入图片描述
spfa(dfs):

#include <bits/stdc++.h>
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#define inf 0x7fffffff
#define ll long long
//#define int long long
//#define double long double
#define eps 1e-5
//#define mod 1e9+7
using namespace std;
const int mod=1e9;
const int N=4e4+5;
int n,m;
struct node
{
	int ver,next;
	double edge1,edge2,dis;
}e[N];
double l,r=200;
int head[N],tot;
double d[N];
int v[N],cnt[N];
bool flag;
void add(int x,int y,double v,double p)
{
	e[++tot].ver=y;
	e[tot].edge1=v;
	e[tot].edge2=p;
	e[tot].next=head[x];
	head[x]=tot;
}
void spfa(int x)
{
	if(flag)  return;
	v[x]=1;
	for(int i=head[x];i;i=e[i].next)
	{
		int y=e[i].ver;
		double z=e[i].dis;
		if(d[y]>d[x]+z)
		{
			d[y]=d[x]+z;
			if(!v[y])  spfa(y);
			else
			{
				flag=1;
				return;
			}
		}
	}
	v[x]=0;
}
signed main()
{
//	ios::sync_with_stdio(false);
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
    	int x,y;
		double v,p;
    	scanf("%d%d%lf%lf",&x,&y,&v,&p);
    	add(x,y,v,p);
    }
    while(r-l>=1e-2)
    {
    	double mid=(r+l)/2;
    	flag=0;
    	for(int i=1;i<=tot;i++)  e[i].dis=e[i].edge2*mid-e[i].edge1;
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=1;j<=n;j++)
	        {
		        v[j]=0;
		        d[j]=1e9;
	        }
    		spfa(i);
    		if(flag)  break;
    	}
    	if(flag)  l=mid;
    	else r=mid;
    }
    if(l==0)  cout<<"-1";
    else printf("%.1lf",r);
    return 0;
}

在这里插入图片描述

bellman-ford

void bellman-ford(int s)
{
	memset(d,0x3f,sizeof(d));
    d[s]=0;
    for(int x=1;x<=n;x++)
        for(int i=head[x];i;i=e[i].next)
        {
        	int y=e[i].ver;
        	int z=e[i].edge;
        	d[y]=min(d[y],d[x]+z);
		}
}
	

扩展和题目就先不说了,期待下一期吧。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值