POJ 1201 解题报告

这道题大部分人用的是差分约束系统。名字很高深,理解起来很比较困难。可以google下。但是实现很简单。其实就是求单源最长路径。这里求“最长”而不是最短的原因是要求d[v] - d[u - 1] >= w。可以理解为在求最长路径的过程中,这些约束已经变成了边的约束,所以求最长路径的过程中这些约束都一一实现了。 

关于邻接链表的实现,如果用vector#push_back边很难通过测试,动态分配空间的开销太大了。这里用的是简单的数组表示的链接(预先分配空间)。能这样做的原因是interval的数目范围题中已经说了(<=50000)。初始化需要注意。

discuss里面第一个帖子(贪心+树状数组+并查集维护)(http://poj.org/showmessage?message_id=347267)看着解法也很简洁。但是目前对树状数组理解不够就先不看了。


thestoryofsnow1201Accepted2392K282MSC++2931B
/* 
ID: thestor1 
LANG: C++ 
TASK: poj1201 
*/
#include <iostream>
#include <fstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <limits>
#include <string>
#include <vector>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <cassert>

using namespace std;

const int MAXN = 50000 + 2;

class Edge{
public:
	int v, w, next;
	Edge() : next(-1) {}
	Edge(int v, int w) : v(v), w(w), next(-1) {}
};

// A node(int) is in range [source, sink]
// To save space, dis array has size `sink - source + 1`
// A node `u` is stored in dis[u - source]
int spfa(int adjs[], Edge edges[], const int source, const int sink)
{
	const int size = sink - source + 1;
	std::vector<int> dis(size, -1);
	std::vector<bool> isInQueue(size, false);
	// set distance of source (from source) as 0
	dis[0] = 0;
	queue<int> que;
	que.push(source);
	isInQueue[0] = true;

	while (!que.empty())
	{
		int u = que.front();
		que.pop();
		isInQueue[u - source] = false;

		int edgeno = adjs[u];
		while (edgeno != -1)
		{
			int v = edges[edgeno].v, w = edges[edgeno].w;
			if (dis[v - source] < dis[u - source] + w)
			{
				dis[v - source] = dis[u - source] + w;
				if (!isInQueue[v - source])
				{
					que.push(v);
					isInQueue[v - source] = true;
				}
			}
			edgeno = edges[edgeno].next;
		}
	}

	return dis[sink - source];
}

void addEdge(int u, int v, int w, int adjs[], Edge edges[], int &edgeno)
{
	edges[edgeno].v = v;
	edges[edgeno].w = w;
	edges[edgeno].next = adjs[u];
	adjs[u] = edgeno;
	edgeno++;
}


int main()
{
	int adjs[MAXN];
	Edge edges[3 * MAXN];

	int n;
	scanf("%d", &n);

	memset(adjs, -1, sizeof(adjs));
	int edgeno = 0;

	int minai = -1, maxbi = -1;
	for (int i = 0; i < n; ++i)
	{
		int ai, bi, ci;
		scanf("%d%d%d", &ai, &bi, &ci);
		ai++, bi++;
		assert(ai - 1 >= 0);

		addEdge(ai - 1, bi, ci, adjs, edges, edgeno);

		if (minai < 0 || minai > ai - 1)
		{
			minai = ai - 1;
		}
		maxbi = max(maxbi, bi);
	}

	const int source = minai, sink = maxbi;
	// d[i + 1] >= d[i] (d[i + 1] - d[i] >= 0)
	// d[i] + 1 >= d[i + 1] (d[i] - d[i + 1] >= -1)
	for (int i = source; i < sink; ++i)
	{
		addEdge(i, i + 1, 0, adjs, edges, edgeno);
		addEdge(i + 1, i, -1, adjs, edges, edgeno);
	}

	// printf("edges:\n");
	// for (int i = 0; i < edgeno; ++i)
	// {
	// 	printf("edgeno: %d, v: %d, w: %d, next: %d\n", i, edges[i].v, edges[i].w, edges[i].next);
	// }


	// printf("adjs:\n");
	// for (int u = source; u <= sink; ++u)
	// {
	// 	int edgeno = adjs[u];
	// 	while (edgeno != -1)
	// 	{
	// 		int v = edges[edgeno].v, w = edges[edgeno].w;
	// 		printf("%d -> %d (%d), edgeno: %d\n", u, v, w, edgeno);
	// 		edgeno = edges[edgeno].next;
	// 	}
	// }

	printf("%d\n", spfa(adjs, edges, source, sink));

	return 0;  
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值