解题报告
题目 :http://poj.org/problem?id=2679
题目大意 :给定一个图,每条边有两个值长度和费用。求A到B的最少花费路且路程尽量短,要求从A到B的最短路中所使用的路,都是某节点的最短出边,设A->C->d>B.那么a->c
就是a的所有出边中最短的(花费边),
算法 :SPFA + 深搜判点是否受影响。
思路 :把每个点的出边在建图时只保留最短边,这个用链表在建图时就很容易能搞定。然后在这个图上,用SPFA求最短路,条件是if(times[u] > n + 5) return 0来判负环。而这个题的难处在于我们也要确定的是在A到B这条路径上有没有环,也就是判断B受不受负环影响,而不是图整体有没有环,利用times值,如果一个点在环上,必有times[p] > n 那么。我们枚举每个点,如果times[p] >n而且p到B有路(深搜一下就能判断)。那么说明A到B是有负环的。
提交情况 :wrong answ 5次 理解错题意
Time limit error 4次 方法不对
Accrpted 一次
经验与收获 :有一次发现自己经常使用的SPFA其实并不是理解的很好,比如说当我们用队列实现的时候,那么我们能够很快的判断出负环,但是不能将所有点最起码的最短路求出来。而队列实现的SPFA能够确保我们为负环外的点找到一条很短的路,这样有助于我们进行其他操作。本题就需要队列,而且,spfa中的times不是仅仅能够判断负环,而且能够标记一个点是不是在负环上(至少能证明一个点可能在负环上)。这样我们能够利用这个信息处理一个点B是否受负环影响,只要从负环上的点开始深搜,看能否到达B即可。
AC code:
#include <stdio.h>
#include <string.h>
#define MAXN 2210
#define MAXM 11000
#define INF 0x33333333
struct NODE{
int to, len, cost, next;
} edges[MAXM];
inthead[MAXN], ad, n, m, A, B, T;
intcost[MAXN], path[MAXN];
voidclear(){
ad = 0;
memset(head, -1, sizeof(head));
}
void insert(int u, int v, int cost, int len){
if(head[u] != -1 && cost > edges[head[u]].cost) return;
if(head[u] != -1 && cost < edges[head[u]].cost) head[u] = -1;
edges[ad].to = v; edges[ad].cost = cost; edges[ad].len = len; edges[ad].next = head[u]; head[u] = ad ++;
}
intqueue[MAXN], in[MAXN], times[MAXN];
int SPFA(int A){
int front = 0, tail = 1;
memset(cost, 0x33, sizeof(cost));
memset(path, 0x33, sizeof(path));
memset(in, 0, sizeof(in));
memset(times, 0, sizeof(times));
queue[front] = A;
cost[A] = path[A] = 0;
in[A] = times[A] = 1;
while(front != tail){
int u = queue[front], v;
front = (front + 1) % MAXN;
in[u] = 0;
if(times[u] > n + 5) return 0;
for(int p = head[u]; ~p; p = edges[p].next){
v = edges[p].to;
if((cost[v] > cost[u] + edges[p].cost) || ((cost[v] == cost[u] + edges[p].cost) && (path[v] > path[u] + edges[p].len))){
cost[v] = cost[u] + edges[p].cost;
path[v] = path[u] + edges[p].len;
if(!in[v]){
queue[tail] = v;
tail = (tail + 1) % MAXN;
in[v] = 1;
times[v] ++;
}
}
}
}
return 1;
}
void dfs(int u){
in[u] = 1;
if(u == B){ T = 1; return;}
for(int p = head[u]; ~p; p = edges[p].next){
if(!in[edges[p].to]) dfs(edges[p].to);
}
}
int main(){
int i, j, u, v, fuv, fvu, len, falg;
char ch;
while(~scanf("%d %d %d %d", &n, &m, &A, &B)){
clear();
for(i = 0; i < m; i ++){
while(scanf("%c", &ch), ch != '(');
scanf("%d,%d,%d[%d]%d)", &u, &v, &fuv, &len, &fvu);
insert(u, v, fuv, len);
insert(v, u, fvu, len);
}
falg = SPFA(A);
if(cost[B] == INF) printf("VOID\n");
else
if(falg) printf("%d %d\n", cost[B], path[B]);
else{
for(i = 0; i < n; i ++){
if(times[i] > n){
memset(in, 0, sizeof(in));
T = 0;
dfs(i);
if(T) break;
}
}
if(T || times[B] > n) printf("UNBOUND\n");
else printf("%d %d\n", cost[B], path[B]);
}
}
return 0;
}