POJ3259 农场与虫洞 图论(Bellman-Ford求负环)


嗯图论的第二道题,刚刚有一点点入门的感觉www。

于是就把心得体会写下来啦。


题目概述:

主人公农夫有几片农场,然后农场里有各个农田(这个模型化为图的端点),然后各个农田之间有路径(这个模型化为图的边),然后有的边是正常的无向边,以及有的边是有项的虫洞。开始的时候时间为0,通过一条正常边会加时间,通过虫洞减去时间。

输入N(1-500),M(1-2500),W(1-100),然后输出能否通过一条路径回到过去,也就是模型中的负权环。

算法思想:

求负权显然的Bellman-Ford,可是还是太慢了要400多MS,不知道先进的方法是怎么样的。果然要看下SPFA么。。

大概跟标准模版无差,值得一提的是,这种算法求负权环有两种方式,第一种是求完最短路径然后继续检查更新,第二种是直接看更新能不能进行到第n-1次,两种代码我都实现了一遍,速度也并没有太大的差异。就列在下面了。

代码部分:

代码1:

#include <iostream>
using namespace std;
int N;int n,m,w;
int MAX = 21474836;

struct edge{
	int from,to,cost;
};

int d[555];bool flag;
edge e[5600];

void init() {
	flag = false;
	cin >> n >> m >> w;
	for (int i=0;i<n;i++){
		d[i] = MAX;
	}
	d[0] = 0;
	for (int i=0;i<2*m;i+=2){
		int a,b,c;
		cin >> a >> b >> c;
		e[i].from = a;
		e[i].to = b;
		e[i].cost = c;
		e[i+1].from = b;
		e[i+1].to = a;
		e[i+1].cost = c;
	}
	for (int i=2*m;i<2*m+w;i++){
		int a,b,c;
		cin >> a >> b >> c;
		e[i].from = a;
		e[i].to = b;
		e[i].cost = c*(-1);
	}
}

bool b_f() {
	for (int i=0;i<n-1;i++){
		for (int j=0;j<2*m+w;j++){
			if (d[e[j].from] != MAX && d[e[j].to] > d[e[j].from]+e[j].cost) {
				d[e[j].to] = d[e[j].from]+e[j].cost;
			}
		}
	}

	for (int j=0;j<2*m+w;j++){
		if (d[e[j].to] > d[e[j].from]+e[j].cost) {
			return true;
		}
	}
	return false;

}


int main() {
	cin >> N;
	for (int k=0; k<N; ++k){
		init();
		if (b_f()) cout << "YES" << endl;
		else cout << "NO" << endl;
	}
	return 0;
}

代码2:

#include <iostream>
#include <string.h>
using namespace std;
int N;int n,m,w;

struct edge{
	int from,to,cost;
};

int d[555];
edge e[5600];

void init() {
	cin >> n >> m >> w;
	memset(d,0,sizeof(d));
	for (int i=0;i<m*2;i+=2){
		int a,b,c;
		cin >> a >> b >> c;
		e[i].from = a;
		e[i].to = b;
		e[i].cost = c;
		e[i+1].from = b;
		e[i+1].to = a;
		e[i+1].cost = c;
	}
	for (int i=2*m;i<2*m+w;i++){
		int a,b,c;
		cin >> a >> b >> c;
		e[i].from = a;
		e[i].to = b;
		e[i].cost = c*(-1);
	}
}

bool b_f() {
	for (int i=0;i<n;i++){
		for (int j=0;j<2*m+w;j++){
			if (d[e[j].to] > d[e[j].from]+e[j].cost) {
				d[e[j].to] = d[e[j].from]+e[j].cost;
				if (i == n-1) return true;
			}
		}
	}
	return false;
}


int main() {
	cin >> N;
	for (int k=0; k<N; ++k){
		init();
		if (b_f()) cout << "YES" << endl;
		else cout << "NO" << endl;
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值