【日常学习】【SPFA负环+数组模拟链表实现】codevs2645 Spore题解

27 篇文章 0 订阅
20 篇文章 0 订阅

之前刚刚写了一道“香甜的黄油”,是USACO的经典题目了。那道题用SPFA怎么找都过不了,看着别人的PAS轻松过各种拙计。黄学长说最佳方案应当是堆优化的dij,我还没有血,等学了那个之后再写黄油题解吧。


题目:

题目描述 Description
在星系1 的某颗美丽的行星之上.某陈将去标号为N 的星系,从星系g1 到达g2,某陈需要花费c1 的代价[主要是燃料,另外还有与沿途Grox 的势力作战的花费],c1 小于0 则是因为 这样的星系旅行,会给某陈带来收益[来源于物流差价,以及一些殖民地的税收..].相应地,c2 则是代表从星系g2 到达g1 的代价.据某陈了解,共有M 条这样的星系间路径. 为了战备,他需要选择一条总代价最小的路线.
输入描述 Input Description
输入文件包括多组数据. 对于每一组数据,第一行有2 个整数n,m,如题目描述中的含义,1<=n<=1000,0<=m<=10000. 接下来的m 行,每行会有四个整数g1,g2,c1,c2,如题目描述中的含义.0<=g1,g2<=n.输入数据保证所有整数都在[- 10000..10000]的范围内. n=0,m=0 标识着输入数据的结束.每个输入文件包含不超过10 组数据.
输出描述 Output Description
对于每组输入数据,输出一行,为从星系1 到星系N 的最小代价的路线的代价. 如果这样的路线不存在,输出'No such path'.
样例输入 Sample Input
3 2 1 2 2 -1 2 3 0 1 0 0
样例输出 Sample Output
2

题目的描述好长,去了没用的部分。

那么,关于这道题,我是第一次写数组模拟链表实现,对于SPFA而言的确提高不少效率,如果加上SLF和LLL可能会效率更高(需要写一个优先队列+结构体并重载定义比较函数)。负环的判断,只要加一个数组就可以了,因为最坏的情况是对于这个点,所有点都会改变,都会松弛这个点,最多松弛n次,就是入队n次。如果进队次数>n,那么一定是出现了负环,一直沿着负环走最短路可以无穷小,因此不存在最短路。


放代码

//codevs2645 Spore SPFA有负环+数组模拟链表
//copyright by ameatke
//first time to right link graph,cheer up!
#include
   
   
    
    
#include
    
    
     
     
#include
     
     
      
      
using namespace std;

int m,n,g1,g2,c1,c2;
int et,head[20001],ld[20001],next[20001],val[20001];
int dis[1001],cnt[1001],inq[1001],flag;
//队列中存的是待松弛的点,head存的是以这个点为起点的第一条编的编号
//next存的是同起点边序列的下一条编的编号
//p是边的编号,每一次从同起点序列的第一条边开始向后遍历,直到next[p]==0说明这是最后一条边 

void insert(int &a,int &b,int &c) 
{
	et++;//et is the number of edge
	ld[et]=b;
	val[et]=c;
	next[et]=head[a];//next edge point to the first edge who has the same start,the last next is 0
	head[a]=et;//turn the first edge to now edge,also a number
}  

void spfa()
{
	queue
      
      
       
        q;
	int p;
	dis[1]=0;
	inq[1]=1;
	cnt[1]=1;
	q.push(1);
	while (!q.empty())
	{
		p=head[q.front()];//p is the number of the first edge whose start is a
		while (p)
		{
			if (dis[q.front()]+val[p]
       
       
         n) { printf("No such path\n");flag=1;return; } if (!inq[ld[p]]) { inq[ld[p]]++; q.push(ld[p]); } } p=next[p]; } inq[q.front()]=0; q.pop(); } return; } int main() { while (scanf("%d%d",&n,&m)&&n) { flag=0;et=0; memset(next,0,sizeof(next)); memset(head,0,sizeof(head)); memset(cnt,0,sizeof(cnt)); memset(inq,0,sizeof(inq)); memset(dis,0x3f,sizeof(dis)); for (int i=0;i 
         
       
      
      
     
     
    
    
   
   

这个很重要,今后也要经常翻看学习


——一道残阳铺水中,半江瑟瑟半江红。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值