这道题大部分人用的是差分约束系统。名字很高深,理解起来很比较困难。可以google下。但是实现很简单。其实就是求单源最长路径。这里求“最长”而不是最短的原因是要求d[v] - d[u - 1] >= w。可以理解为在求最长路径的过程中,这些约束已经变成了边的约束,所以求最长路径的过程中这些约束都一一实现了。
关于邻接链表的实现,如果用vector#push_back边很难通过测试,动态分配空间的开销太大了。这里用的是简单的数组表示的链接(预先分配空间)。能这样做的原因是interval的数目范围题中已经说了(<=50000)。初始化需要注意。
discuss里面第一个帖子(贪心+树状数组+并查集维护)(http://poj.org/showmessage?message_id=347267)看着解法也很简洁。但是目前对树状数组理解不够就先不看了。
thestoryofsnow | 1201 | Accepted | 2392K | 282MS | C++ | 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;
}