可以用来做模板的题目。对于约束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;
}

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

posted on 2012-04-07 18:24    阅读(202)  评论(0编辑  收藏  举报