pku3159 差分约束系统(SPFA + 栈)

Candies

小孩A认为小孩B比自己多出的最多不会超过c个糖果,也就是 B - A <= c,正好符合差分约束方程,就是A到B的边权w(A, B) = c;用 SPFA + 栈 能过。

这里有两种加边方式:

第一种:我以前用的,用这个超时了,因为每次加边都是将边夹在邻接表的最后面,需要一个查找时间,这题数据量大,自然就超时了。

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
void add( int a, int b, int c){
int tmp;
edge[edNum].e
= b;
edge[edNum].v
= c;
next[edNum]
= - 1 ;
tmp
= root[a];
if (tmp == - 1 ){
root[a]
= edNum;
}
else {
while (next[tmp] != - 1 ){
tmp
= next[tmp];
}
next[tmp]
= edNum;
}
edNum
++ ;
}

第二种:这种我刚学到的,比较好,每次把边加在最前面,突然想起sjr有一道题的加边方法和这个一样,那时怎么就看不懂,大概是不懂邻接表的缘故吧。

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

 这题还得用栈实现,用队列超时,我开始用队列,一直TLE,我这里写了两个,Spfa()是用队列实现的,Spfa1是用栈实现的。

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
#include < stdio.h >
#include
< stdlib.h >
#include
< string .h >
#define INF 0xfffffff
#define MM 150004
#define NN 30004
int edNum, N;
struct node{
int e, v;
}edge[MM];

int next[MM];
int dis[NN];
int root[NN];
int que[NN];
int mark[NN];
int stack[NN];

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

void Spfa()
{
int i, quNum, tmp, nxt, cur;
for (i = 1 ; i <= N; i ++ ){
dis[i]
= INF;
}
dis[
1 ] = 0 ;
quNum
= 0 ;
for (i = 1 ; i <= N; i ++ ){
if (root[i] != - 1 ){
que[quNum
++ ] = i;
mark[i]
= 1 ;
}
}

for (i = 0 ; i != quNum; i = (i + 1 ) % (N + 1 )){
cur
= que[i];
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 ;
que[quNum]
= nxt;
quNum
= (quNum + 1 ) % (N + 1 );
}
}
tmp
= next[tmp];
}
mark[cur]
= 0 ;
}
}

void Spfa1()
{
int i, top, tmp, nxt, cur;
for (i = 1 ; i <= N; i ++ ){
dis[i]
= INF;
}
dis[
1 ] = 0 ;
top
= 0 ;

for (i = 1 ; i <= N; i ++ ){
if (root[i] != - 1 ){
stack[
++ top] = i;
mark[i]
= 1 ;
}
}

while (top){
cur
= stack[top -- ];
tmp
= root[cur];
mark[cur]
= 0 ;
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
= next[tmp];
}

}
}

int main()
{
int M, a, b, c, i;
scanf(
" %d%d " , & N, & M);
edNum
= 0 ;
for (i = 0 ; i <= N; i ++ ){
root[i]
= - 1 ;
mark[i]
= 0 ;
}
while (M -- ){
scanf(
" %d%d%d " , & a, & b, & c);
add(a, b, c);
}
Spfa1();
printf(
" %d\n " , dis[N]);
// system("pause");
return 0 ;
}

 

转载于:https://www.cnblogs.com/ylfdrib/archive/2010/07/21/1782492.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值