pku1201 Intervals

这题目,我差点彻底崩溃了,郁闷死了,一开始一直TLE,原来只有一个测试数据,这叫我情何以堪……

后来,还发现了一个错误,就是构图时候,最大节点跟最小节点还是要标记一下比较好,我本来是默认0是最小节点的,可是在后面添加新边的时候又添加了一个0节点,唉

就是Sbi+1-Sai>=Ci,这样来添加边计较保险

用数组模拟队列来实现SPFA的时候,数组要绝对的足够大,我就这样RE了无数次,最后Q[maxn*10]才过的,但此时内存已经很大了

不过也可以直接用STL里面的queue来做,方便很多,内存也不算很大

还有用栈实现的,这个就很省内存啦

为什么用栈写有时候会很快呢? 首先它很节省空间,因为最多有v-1个节点同时在栈内。其次,它在栈底的点并不容易出栈,所以等到这些节点出栈的时候,它已经被松弛的差不多了。说白了还是一个概率型优化方法。
spfa是一个不稳定的算法,用队列实现有点像广搜。当然大家可以用深搜实现一下。因为即使用栈写,那也是广度优先搜索的思路。因为它是‘一层一层’执行,而深搜是‘一个一个’执行。所以用深搜的思路写,效率可想而知了。

下面是俩种方式的SPFA:

数组模拟队列实现
#include <iostream>
#include
<algorithm>
#include
<queue>
using namespace std;
#define MAXN 50005
#define INF 0x6fffffff
struct Edge{
int v;
int w;
int next;
}edge[
150000];
int head[MAXN];
bool vis[MAXN];
int dis[MAXN];
int stack[MAXN*10];
int n;
int ind;
int Max,Min;

void add_edge(int u,int v,int w)
{
edge[ind].v
=v;
edge[ind].w
=w;
edge[ind].next
=head[u];
head[u]
=ind++;
}
void Init(int e)
{
for(int i=0;i<=e;i++)
{
vis[i]
=false;
dis[i]
=-INF;
}
}
void spfa()
{
Init(Max);
dis[Min]
=0;
int begin,end;
begin
= end = 0;
stack[end
++] = Min;
vis[Min]
= true;
while(begin<end)
{
int t = stack[begin++];
for(int j = head[t];j!=-1;j = edge[j].next)
{
if(dis[edge[j].v]<edge[j].w+dis[t])
{
dis[edge[j].v]
= edge[j].w+dis[t];
if(!vis[edge[j].v])
{
vis[edge[j].v]
= true;
stack[end
++] = edge[j].v;
}
}
}
vis[t]
= false;
}
}

int main() {
scanf(
"%d",&n);
memset(head,
-1,sizeof(head));
int u,v,w;
ind
=0;
Max
=0;Min=INF;
for(int i=1;i<=n;i++)
{
scanf(
"%d%d%d",&u,&v,&w);
if(v+1>Max)Max=v+1;
if(u<Min)Min=u;
add_edge(u,v
+1,w);
}
for(int i=Min;i<Max;i++)
{
add_edge(i,i
+1,0);
add_edge(i
+1,i,-1);
}
spfa();
// for(int i=Min;i<=Max;i++)printf("%d\n",dis[i]);
printf("%d\n",dis[Max]);
//printf("%d %d\n",Max,Min);
return 0;
}
用数组模拟栈实现
#include<stdio.h>
#include
<stdlib.h>
#define INF 0xfffffff
#define NN 50004
#define MM 150004
int edNum, maxn;
int mark[NN];
int root[NN];
int dis[NN];
int stack[NN];
struct node{
int e, v,next;
}edge[MM];

void Init(){
int i;
for (i = 0; i < NN; i++){
mark[i]
= 0;
root[i]
= -1;
dis[i]
= INF;
}
}

void add(int a, int b, int c){
edge[edNum].e
= b;
edge[edNum].v
= c;
edge[edNum].next
= root[a];
root[a]
= edNum++;
}

void Spfa()
{
int i, cur, nxt, tmp, top = 0;
for (i = 0; i <= maxn; i++){
if (root[i] != -1){
stack[
++top] = i;
mark[i]
= 1;
}
}
// 这里需要注意,要将终点置零,求的就是别的点到终点maxn的距离
dis[maxn] = 0;
while (top){
cur
= stack[top--];
mark[cur]
= 0;
tmp
= root[cur];
while (tmp != -1){
nxt
= edge[tmp].e;
if (dis[nxt] > dis[cur] + edge[tmp].v){
dis[nxt]
= dis[cur] + edge[tmp].v;
if (!mark[nxt]){
mark[nxt]
= 1;
stack[
++top] = nxt;
}
}
tmp
=edge[tmp].next;
}
}
}
int main()
{
int n, i, a, b, c;
scanf(
"%d", &n);
maxn
= 0;
edNum
= 0;
Init();
for (i = 1; i <= n; i++){
scanf(
"%d%d%d", &a, &b, &c);
add(b
+ 1, a, -c);
if (b + 1 > maxn){
maxn
= b + 1;
}
}
for (i = 0; i <= maxn; i++){
add(i
+ 1, i, 0);
add(i, i
+ 1, 1);
}
Spfa();
//输出的时候也要注意,是起点到终点的距离的负值
printf("%d\n", -dis[0]);
// system("pause");
return 0;
}




原文地址:https://www.cnblogs.com/nanke/p/2137082.html