poj 3169 Layout 差分约束 最短路

可以用来做模板的题目。对于约束Vj - Vi <= C, 建立一条边 Vi->Vj,权值为C。而对于 Vj - Vi >=C, 两边同时乘以-1,Vi - Vj <= -C,建立一条边Vj -> Vi,权值为-C。建好图以后,求从起点到终点的最短路径,即为本题的答案。

原题目地址:http://poj.org/problem?id=3169

下面是用Bellman_ford优化版本来做做短路径的代码:

//如果出现负环,说明各种约束不能同时成立
#include<stdio.h>
#define max_n 1005
#define INF 0x3fffffff

int w[max_n][max_n];
int dis[max_n];

bool bellman_ford(int N){
int i, j, t;
bool relaxed;
for(i=1; i<=N; i++)
dis[i] = INF;
dis[1] = 0;
for(t=1; t<=N; t++){
relaxed = false;
for(i=1; i<=N; i++){
for(j=1; j<=N; j++){
if(i != j && dis[i] + w[i][j] < dis[j]){
dis[j] = dis[i] + w[i][j];
relaxed = true;
}
}
}
if(!relaxed)
break;
}
for(i=1; i<=N; i++)
for(j=1; j<=N; j++)
if(i != j && dis[i] + w[i][j] < dis[j])
return false;
return true;
}


int main(){
int N, ML, MD;
int i, j, u, v, d;
scanf("%d %d %d",&N, &ML, &MD);
for(i=0; i<=N; i++)
for(j=0; j<=N; j++)
w[i][j] = INF;
for(i=0; i<ML; i++){
scanf("%d %d %d",&u, &v, &d);
w[u][v] = d;
}
for(i=0; i<MD; i++){
scanf("%d %d %d",&u, &v, &d);
w[v][u] = -d; //不等式左右都乘以-1
}
if(!bellman_ford(N))
printf("-1\n");
else if(dis[N] >= INF)
printf("-2\n");
else printf("%d\n",dis[N]);
return 0;
}

下面使用spfa算法写最短路径的代码:

//如果出现负环,说明各种约束不能同时成立
#include<stdio.h>
#define max_n 1005
#define INF 0x3fffffff

int w[max_n][max_n]; //u,v边权
int dis[max_n], vis[max_n];//每个点的距离,每个点被访问的次数
int queue[max_n], head, tail;
bool inq[max_n];//点是否在队列里

bool spfa(int N, int s){
int i, u, v;
head = tail = 0;
queue[tail++] = s;
for(i=0; i<=N; i++){
dis[i] = INF; vis[i] = 0; inq[i] = false;
}
dis[s] = 0; vis[s] = 1; inq[s] = true;
while(head != tail ){
if(head >= max_n)
head = 0;
u = queue[head];
for(v=1; v<=N; v++){
if(u != v && dis[u] + w[u][v] < dis[v]){
dis[v] = dis[u] + w[u][v];
if(!inq[v]){
queue[tail] = v;
tail++;
if(tail >= max_n)
tail = 0;
vis[v]++; //用来判断有无负环
inq[v] = true;
}
if(vis[v] >= N)
return false;
}
}
inq[u] = false;
head++;
}
return true;
}

int main(){
int N, ML, MD;
int i, j, u, v, d;
scanf("%d %d %d",&N, &ML, &MD);
for(i=0; i<=N; i++)
for(j=0; j<=N; j++)
w[i][j] = INF;
for(i=0; i<ML; i++){
scanf("%d %d %d",&u, &v, &d);
w[u][v] = d;
}
for(i=0; i<MD; i++){
scanf("%d %d %d",&u, &v, &d);
w[v][u] = -d; //不等式左右都乘以-1
}
if(!spfa(N, 1))
printf("-1\n");
else if(dis[N] >= INF)
printf("-2\n");
else printf("%d\n",dis[N]);
return 0;
}

速度比上面的快了一点,但是用邻接表会更快的

转载于:https://www.cnblogs.com/qianqiang/archive/2012/04/07/2436342.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值