posts - 43,  comments - 9,  trackbacks - 0

求所谓的 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, 0sizeof(gt));
 33    memset(gg, 0sizeof(gg));
 34    memset(re, 0x7fsizeof(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]==truecontinue;
 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, 0sizeof(cn)); //入列次数 
 67    for(i=0; i<N; i++){
 68        di[i] = wi[i] = INF;
 69    }

 70    memset(inq, falsesizeof(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]==falsecontinue;
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 阅读(252) 评论(0)  编辑 收藏 引用 所属分类: acm_icpcalgorithm

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


<2009年5月>
262728293012
3456789
10111213141516
17181920212223
24252627282930
31123456

"Do not spend all your time on training or studying - this way you will probably become very exhausted and unwilling to compete more. Whatever you do - have fun. Once you find programming is no fun anymore – drop it. Play soccer, find a girlfriend, study something not related to programming, just live a life - programming contests are only programming contests, and nothing more. Don't let them become your life - for your life is much more interesting and colorful." -- Petr

留言簿(3)

随笔分类(59)

随笔档案(43)

cows

搜索

  •  

最新评论

评论排行榜