求所谓的 optimal path:
对某个顶点,只能沿着它所有出边中weight最小的那些路走;
从起点到终点的总weight最小;
如果有weight相同的,取总length最短的.
可能有负环,自环,平行边.
先将不符合要求的边删掉.
接着,关键在于如何判断有效负环,即该负环处在起点到终点的路上.
实际上,只用保留原图中从起点能到达,并且能到达终点的顶点.
如果用标准bellman-ford,需要2次DFS:从起点开始沿边的方向DFS,标记能到达的点;从终点开始沿边的逆向DFS,标记点.
2次都被标记到的点,才是实际有效点.将剩余点删掉.
如果用SPFA,只用执行逆向DFS,因为SPFA本身的扩展是从起点开始沿正向搜索扩展的.
可以建个新图,回避删边删点的麻烦.
无法到达,输出VOID:之前从终点开始的DFS无法到达起点
weight无下界,输出UNBOUND:新图中存在关于weight的负环
要注意松弛操作weight的优先级最高...我居然犯这么低级的错误.
最后若有界解存在,输出wi[B]和di[B]
ps. 如果这题改成: 求length最短的路径中,weight最小的路径,就不一样了,得判断负环是不是在起点到终点的必经之路上,如果不是,还要不断走负环,使得在lenght最短的前提下,weight取尽量大.
1#include <iostream>
2using namespace std;
3
4const int MAXQ = 65536;
5const int INF = -0x7fffffff;
6
7struct EDGE{
8 int v,e,w,l;
9}edg[5100*8];
10int se, gt[1100],gg[1100]; //原图,新图
11int cn[1100], re[1100], di[1100],wi[1100]; //顶点入列次数, 顶点rewarding边权, dist, weight
12bool ok[1100],inq[1100]; //能否到达终点, 是否在队列中
13int que[MAXQ],pq,sq;
14int ansW,ansL;
15int N,M,A,B;
16
17inline void addedge(int u, int v, int w, int l, int g[]){
18 edg[se].v = v;
19 edg[se].w = w;
20 edg[se].l = l;
21 edg[se].e = g[u];
22 g[u] = se++;
23}
24
25inline void skp(char c){
26 while(getchar()!=c);
27}
28
29bool input(){
30 int i,j,k,u,v,wf,wb,l;
31 se = 2;
32 memset(gt, 0, sizeof(gt));
33 memset(gg, 0, sizeof(gg));
34 memset(re, 0x7f, sizeof(re));
35 if(scanf("%d%d",&N,&M)==EOF) return false;
36 scanf("%d%d",&A,&B);
37 for(i=0; i<M; i++){
38 skp('('); scanf("%d",&u);
39 skp(','); scanf("%d",&v);
40 skp(','); scanf("%d",&wf);
41 skp('['); scanf("%d",&l);
42 skp(']'); scanf("%d",&wb);
43 skp(')');
44 addedge(u,v,wf,l,gt);
45 addedge(v,u,wb,l,gt);
46 re[u] = min(re[u], wf);
47 re[v] = min(re[v], wb);
48 }
49 return true;
50}
51
52void dfs(int r){ //从B开始沿反向边遍历
53 int i,j,k;
54 ok[r]=true;
55 for(j=gt[r]; j>0; j=edg[j].e){
56 if(ok[edg[j].v]==true) continue;
57 if(edg[j^1].w == re[edg[j].v])
58 dfs(edg[j].v);
59 }
60}
61
62
63bool spfa(){
64 int i,j,k,u,v,w;
65 bool flag;
66 memset(cn, 0, sizeof(cn)); //入列次数
67 for(i=0; i<N; i++){
68 di[i] = wi[i] = INF;
69 }
70 memset(inq, false, sizeof(inq)); //是否在队列中
71 pq = sq = 0;
72 que[sq++] = A;
73 di[A] = 0; wi[A] = 0;
74 while(pq!=sq){
75 u = que[pq]; inq[u]=false;
76 if(++pq == MAXQ) pq=0;
77 for(j=gg[u]; j>0; j=edg[j].e){
78 v = edg[j].v; flag = false; //是否有松弛操作
79 if(wi[v] == INF || wi[v]>wi[u]+edg[j].w){ //对weight,优先级最高
80 flag=true;
81 wi[v] = wi[u]+edg[j].w;
82 di[v] = di[u]+edg[j].l;
83 if(inq[v]==false && ++cn[v]>N*2) //判断负环
84 return false;
85 }
86 else if(wi[v]==wi[u]+edg[j].w){
87 if(di[v] == INF || di[v]>di[u]+edg[j].l){ //对length
88 flag=true;
89 di[v] = di[u]+edg[j].l;
90 }
91 }
92 if(inq[v]==false && flag==true){
93 inq[v]=true;
94 que[sq] = v;
95 if(++sq == MAXQ) sq=0;
96 }
97 }
98 }
99 ansW = wi[B];
100 ansL = di[B];
101 return true;
102}
103
104
105void solve(){
106 int i,j,k;
107
108 memset(ok,false,sizeof(ok));
109 dfs(B);
110 if(ok[A]==false){
111 puts("VOID"); return ;
112 }
113 for(i=0; i<N; i++){ //建新图
114 if(ok[i]==false) continue;
115 for(j=gt[i]; j>0; j=edg[j].e){
116 if(edg[j].w == re[i] && ok[edg[j].v]==true){
117 addedge(i, edg[j].v, edg[j].w, edg[j].l, gg);
118 //printf("%d,%d(%d,%d) ",i,edg[j].v,edg[j].w,edg[j].l);
119 }
120 }
121 }
122 ansL = ansW = 0x7fffffff;
123 if(spfa()==false){
124 puts("UNBOUND"); return ;
125 }
126 printf("%d %d\n",ansW,ansL);
127}
128
129
130int main(){
131 while(input()){
132 solve();
133 }
134 return 0;
135}
posted on 2009-05-06 11:17
wolf5x 阅读(255)
评论(0) 编辑 收藏 引用 所属分类:
acm_icpc 、
algorithm