sdut 2493 Constructing Roads (图论)

http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2493

好纠结 这么道  破题  比赛是竟然 没做出来  ,比赛 完后  加了个 条件就对了 ,为什么 比赛时 那么 没状态   。。。。。。。。。。。

题意:给出一个无向图  ,一个 原点 s  一个终点  t  求 一条 最短的路径 值 从 s 到 t  ,对于 这条路径  可以 将  其中的 一条边的权值 减半。

 

题解 :  dij +  枚举

   首先  我们可以 得到 知道   对于 t  来说  最小值  = min(与他 连接的点的 最小值  +  w[i][t],    s 到  i  的 最短距离   +  w[i][t] / 2) ;

 所以 我们 得到 状态方程 

   dp[i] 记录  i  的  最终解  dis[i]记录  最短路径 

 

    设  x  与  i  相连

    dp[i] = min(dp[i] ,min(dp[x] + w[i][x],dis[x] + w[i][x] / 2)) ;

 

ExpandedBlockStart.gif View Code
  1 #include<cstdio>
  2 #include<cstring>
  3 #include<cmath>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include< set>
  7 #include<map>
  8 #include<queue>
  9 #include<vector>
 10 #include< string>
 11  #define inf 99999999
 12  #define maxn 1500
 13  #define CL(a,b) memset(a,b,sizeof(a))
 14  #define  ll  long long
 15  // #define mx 1000010
 16  using  namespace std;
 17  int n , m ;
 18  int s,t ;
 19  int dis[maxn],vis[maxn],pre[maxn] ;
 20  int mat[maxn][maxn] ;
 21  int dp[maxn] ;
 22  int solve( int s, int t)
 23 {
 24      int i , j ;
 25      for(i =  0;i<= n;i++)
 26     {
 27         dis[i] = mat[s][i] ;
 28     }
 29     dis[s] =  0 ;
 30 
 31 
 32     CL(vis, 0) ;
 33 
 34 
 35 
 36      int k ;
 37      for(i =  0 ; i < n;i++)
 38     {
 39          int mi = inf ;
 40         k =  0 ;
 41          for(j =  1 ; j <= n;j++)
 42         {
 43              if(!vis[j]&& dis[j] != inf && dis[j] < mi)
 44             {
 45                 mi = dis[j] ;
 46                 k =  j ;
 47             }
 48         }
 49 
 50          if(k ==  0break ;
 51 
 52         vis[k] =  1 ;
 53 
 54 
 55          for(j =  1 ; j <= n;j++)
 56         {
 57              if(!vis[j] && mat[k][j] != inf && dis[j] > dis[k] + mat[k][j])
 58             {
 59 
 60                 dis[j] = dis[k] +  mat[k][j] ;
 61 
 62             }
 63         }
 64     }
 65 
 66 
 67 
 68 
 69 
 70      if(dis[t] >= inf)  return - 1 ;
 71 
 72 
 73      for(i =  0; i<= n;i++)
 74     {
 75         dp[i] = mat[s][i];
 76     }
 77 
 78     dp[s] =  0 ;
 79 
 80      for(i =  1; i <= n;i++)
 81     {
 82 
 83          for(j =  1; j <= n;j++)
 84         {
 85              if(j == s||i == j) continue ;
 86              if(mat[i][j]!=inf)
 87             {
 88                 dp[j] = min(dp[j],min(dp[i] + mat[i][j] ,dis[i] + mat[i][j]/ 2)) ;
 89             }
 90         }
 91     }
 92 
 93      return dp[t] ;
 94 
 95 
 96 }
 97  int main()
 98 {
 99      int i , j,u,v,w  ;
100      while(scanf( " %d%d ",&n,&m)!=EOF)
101     {
102 
103          for(i =  0; i <= n;i++)
104         {
105              for(j =  0 ; j <= n;j++)
106              mat[i][j] = mat[j][i] = inf ;
107 
108             mat[i][i] =  0 ;
109         }
110 
111          for(i =  0; i < m;i++)
112         {
113             scanf( " %d%d%d ",&u,&v,&w);
114              if(w < mat[u][v])
115             mat[u][v] = mat[v][u] = w ;
116         }
117         scanf( " %d%d ",&s,&t) ;
118          int ans = solve(s,t) ;
119 
120          if(ans == - 1)printf( " No solution\n ");
121          else
122             printf( " %d\n ",ans) ;
123     }
124 }

 

 

 

 

转载于:https://www.cnblogs.com/acSzz/archive/2012/12/02/2798489.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值