java计算最长路径spfa,POJ 1201 Intervals(差分约束+spfa 求最长路径)

Description

You are given n closed, integer intervals [ai, bi] and n integers c1, ..., cn.

Write a program that:

reads the number of intervals, their end points and integers c1, ..., cn from the standard input,

computes the minimal size of a set Z of integers which has at least ci common elements with interval [ai, bi], for each i=1,2,...,n,

writes the answer to the standard output.

Input

The first line of the input contains an integer n (1 <= n <= 50000) -- the number of intervals. The following n lines describe the intervals. The (i+1)-th line of the input contains three integers ai, bi and ci separated by single spaces and such that 0 <=

ai <= bi <= 50000 and 1 <= ci <= bi - ai+1.

Output

The output contains exactly one integer equal to the minimal size of set Z sharing at least ci elements with interval [ai, bi], for each i=1,2,...,n.

Sample Input

5

3 7 3

8 10 3

6 8 1

1 3 1

10 11 1

Sample Output

6

Source

题意:(转)

[ai, bi]区间内和点集Z至少有ci个共同元素,那也就是说如果我用Si表示区间[0,i]区间内至少有多少个元素的话,那么Sbi - Sai >= ci,这样我们就构造出来了一系列边,权值为ci,但是这远远不够,因为有很多点依然没有相连接起来(也就是从起点可能根本就还没有到终点的路线),此时,我们再看看Si的定义,也不难写出0<=Si

- Si-1<=1的限制条件,虽然看上去是没有什么意义的条件,但是如果你也把它构造出一系列的边的话,这样从起点到终点的最短路也就顺理成章的出现了。

我们将上面的限制条件写为同意的形式:

Sbi - Sai >= ci

Si - Si-1 >= 0

Si-1 - Si >= -1

这样一来就构造出了三种权值的边,而最短路自然也就没问题了。

但要注意的是,由于查分约束系统里常常会有负权边,所以为了避免负权回路,往往用Bellman-Ford或是SPFA求解(存在负权回路则最短路不存在)。

PS:

因为求的是[ai,bi]区间,所以我们添加边的时候需要(u-1, v, w)!

把距离dis初始化为负无穷, if(dis[v] < dis[u] + w)即可!

代码如下:

#include

#include

#include

#include

#include

using namespace std;

#define INF 0x3f3f3f3f

#define N 50017

#define M 50017

int n, m, k;

int Edgehead[N], dis[N];

struct Edge

{

int v,w,next;

} Edge[3*M];

bool vis[N];

//int cont[N];

int minn, maxx;

int MIN(int a, int b)

{

if(a < b)

return a;

return b;

}

int MAX(int a, int b)

{

if(a > b)

return a;

return b;

}

void Addedge(int u, int v, int w)

{

Edge[k].next = Edgehead[u];

Edge[k].w = w;

Edge[k].v = v;

Edgehead[u] = k++;

}

int SPFA( int start)//stack

{

int sta[N];

int top = 0;

for(int i = 1 ; i <= n ; i++ )

dis[i] = -INF;

dis[start] = 0;

//++cont[start];

memset(vis,false,sizeof(vis));

sta[++top] = start;

vis[start] = true;

while(top)

{

int u = sta[top--];

vis[u] = false;

for(int i = Edgehead[u]; i != -1; i = Edge[i].next)//注意

{

int v = Edge[i].v;

int w = Edge[i].w;

if(dis[v] < dis[u] + w)

{

dis[v] = dis[u]+w;

if( !vis[v] )//防止出现环

{

sta[++top] = v;

vis[v] = true;

}

//if(++cont[v] > n)//有负环

//return -1;

}

}

}

return dis[maxx];

}

int main()

{

int u, v, w;

while(~scanf("%d",&n))//n为目的地

{

k = 1;

memset(Edgehead,-1,sizeof(Edgehead));

minn = INF;

maxx = -1;

for(int i = 1 ; i <= n ; i++ )

{

scanf("%d%d%d",&u,&v,&w);

Addedge(u-1,v,w);

maxx = MAX(v,maxx);

minn = MIN(u-1,minn);

}

for(int i = minn; i <= maxx; i++)//新边,保证图的连通性还必须添加每相邻两个整数点i,i+1的边

{

Addedge(i,i+1,0);

Addedge(i+1,i,-1);

}

int ans = SPFA(minn);//从点minn开始寻找最短路

printf("%d\n",ans);

}

return 0;

}

版权声明:本文为博主原创文章,未经博主允许不得转载。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值