最短路

来源:互联网 发布:数据分析师女生做累么 编辑:程序博客网 时间:2024/06/04 19:43
POJ 1724

一个优先队列+dij  一个dfs+剪枝
dfs更好理解,不过优先队列留着,以后在学习学习

dfs版本:
 
  1.   
  2. #include<iostream>  
  3. using namespace std;  
  4.   
  5. const int inf=1e7;  
  6. const int CitySize=101;  
  7. const int RoadSize=10001;  
  8.   
  9. struct  
  10. {  
  11.     int S,D,L,T;  //Source,Destination,Length,Toll  
  12.     int next;     //指向相同Source的下一条边  
  13. }road[RoadSize];  
  14.   
  15. int pr;   //road[]指针  
  16. int K,N,R;  //Money,CityNum,RoadNum  
  17. int MinLen;  
  18. bool vist[CitySize];  
  19. int ListTable_Head[CitySize];  //邻接链表头指针数组  
  20.   
  21. void DFS(int NowCity,int NowLen,int RestMoney)  
  22. {  
  23.     if(NowLen>MinLen)  
  24.         return;  
  25.   
  26.     if(NowCity==N && RestMoney>=0 && NowLen<MinLen)  
  27.     {  
  28.         MinLen=NowLen;  
  29.         return;  
  30.     }  
  31.   
  32.     for(int i=ListTable_Head[NowCity];i!=-1;i=road[i].next)  
  33.     {  
  34.         int tD=road[i].D;  
  35.         int tL=road[i].L;  
  36.         int tT=road[i].T;  
  37.   
  38.         if(!vist[tD] && RestMoney>=tT)  
  39.         {  
  40.             vist[tD]=true;  
  41.             DFS(tD,NowLen+tL,RestMoney-tT);  
  42.             vist[tD]=false;  
  43.         }  
  44.     }  
  45.     return;  
  46. }  
  47.   
  48. int main(void)  
  49. {  
  50.     while(cin>>K>>N>>R)  
  51.     {  
  52.         memset(ListTable_Head,-1,sizeof(ListTable_Head));  
  53.         memset(vist,false,sizeof(vist));  
  54.         pr=0;  
  55.         MinLen=inf;  
  56.   
  57.         for(int i=1;i<=R;i++)  
  58.         {  
  59.             int s,d,l,t;  
  60.             cin>>s>>d>>l>>t;  
  61.             road[pr].S=s;  
  62.             road[pr].D=d;  
  63.             road[pr].L=l;  
  64.             road[pr].T=t;  
  65.             road[pr].next=ListTable_Head[s];  
  66.             ListTable_Head[s]=pr++;  
  67.         }  
  68.   
  69.         DFS(1,0,K);  
  70.   
  71.         cout<<(MinLen<inf?MinLen:-1)<<endl;  
  72.     }  
  73.     return 0;  
  74. }  
     
  75.  
  76.  
  77. #include <cstdio>
  78. #include <cstring>
  79. #include <vector>
  80. #include <queue>
  81. #include <algorithm>
  82. using namespace std;
  83. #define N 110
  84. #define M 10010
  85. #define INF 0x3f3f3f3f

  86. int n,m,cost,tot;
  87. struct State
  88. {
  89.    int n,d,c;
  90.    bool operator < (const struct State a)const
  91.    {
  92.       if(a.d == d) return a.c < c;
  93.       return a.d < d;
  94.    }
  95. };
  96. struct edge
  97. {
  98.    int u,v,w,c,next;
  99. };
  100. typedef struct State State;
  101. typedef struct edge edge;
  102. int head[N];
  103. int d[N];
  104. edge e[M];


  105. void add(int u , int v , int w , int c)
  106. {
  107.    e[tot].u = u; e[tot].v = v; e[tot].w = w; e[tot].c = c;
  108.    e[tot].next = head[u]; head[u] = tot++;
  109. }

  110. void Dij()
  111. {
  112.    priority_queue<State>q;
  113.    State sta;
  114.    int res = INF ;
  115.    memset(d,0x3f,sizeof(d));
  116.    while(!q.empty()) q.pop();
  117.    sta.d = 0;
  118.    sta.n = 1;
  119.    sta.c = 0;
  120.    q.push(sta);
  121.    while(!q.empty())
  122.    {
  123.       State x,y;
  124.       int u,v,w,d,c;

  125.       x = q.top(); q.pop();
  126.       u = x.n; d = x.d;

  127.       if(u == n)
  128.       {
  129.          res = x.d;
  130.          break;
  131.       }

  132.       for(int k=head[u]; k!=-1; k=e[k].next)
  133.       {
  134.          v = e[k].v; w = e[k].w; c = e[k].c;
  135.          if(x.c + c <= cost) //在花费允许的范围内可以去到这个点
  136.          {
  137.             y.n = v;  y.d = d + w;  y.c = x.c + c;
  138.             q.push(y);
  139.          }
  140.       }
  141.    }
  142.    if(res == INF) printf("-1\n");
  143.    else           printf("%d\n",res);
  144. }

  145. int main()
  146. {
  147.    scanf("%d%d%d",&cost,&n,&m);
  148.    memset(head,-1,sizeof(head));
  149.    tot = 0;
  150.    while(m--)
  151.    {
  152.       int u,v,w,c; 
  153.       scanf("%d%d%d%d",&u,&v,&w,&c);
  154.       add(u,v,w,c);
  155.    }
  156.    Dij();
  157.    return 0;
  158. }
HDU 1839
注意这道题是求最大流量最短路,刚刚那道题是求最短时间最短路。
 ①二分+Dij最短路

题目大意:
有N个点,点1为珍贵矿物的采矿区, 点N为加工厂,有M条双向连通的边连接这些点。走每条边的运输容量为C,运送时间为D。
他们要选择一条从1到N的路径运输, 这条路径的运输总时间要在T之内,在这个前提之下,要让这条路径的运输容量尽可能地大。
一条路径的运输容量取决与这条路径中的运输容量最小的那条边。

(这题就是二分最小容量,对满足容量的加边,对时间求最短路。如果最短时间比规定时间少的话就可以继续增加容量,直到不能增加为止。)

分析与总结:

因为每条路径的容量取决于这条路径中所有边中的最小容量,所以我们可以以此枚举最小容量。

但是如果一个一个容量的枚举,那明显效率太低了。

通过分析,可以看出,如果最低容量越大,那么符合要求的路径就越少,所以,根据容量的大小,路径数量是单调的。

有了单调性,就可以利用二分法了

只要把容量从大到小进行排序,然后二分之,很快便能算出答案。 

  1. #include<iostream>  
  2. #include<cstdio>  
  3. #include<cstring>  
  4. #include<algorithm>  
  5. #include<queue>  
  6. using namespace std;  
  7.   
  8. const int INF = 0x7fffffff;  
  9. const int VN  =  10005;  
  10. const int EN  =  50005;  
  11.   
  12. struct Edge{int v,next,cap,time;}E[EN*2];  
  13.   
  14. int n, m, t;  
  15. int size;  
  16. int head[VN];  
  17. int cap[EN];  
  18. int d[VN];  
  19. int Time[VN];  
  20. int limit;  
  21. bool inq[VN];  
  22.   
  23. void init(){  
  24.     size=0;  
  25.     memset(head, -1, sizeof(head));  
  26. }  
  27. void addEdge(int u,int v,int c,int d){  
  28.     E[size].v=v;  
  29.     E[size].cap=c;  
  30.     E[size].time=d;  
  31.     E[size].next = head[u];  
  32.     head[u] = size++;  
  33. }  
  34. int Dijkstra(int src){  
  35.     memset(inq, 0, sizeof(inq));  
  36.     for(int i=1; i<=n; ++i)d[i]=INF;  
  37.     d[src] = 0;  
  38.     queue<int>q;  
  39.     q.push(src);  
  40.     while(!q.empty()){  
  41.         int u = q.front(); q.pop();  
  42.         inq[u] = false;  
  43.         for(int e=head[u]; e!=-1; e=E[e].next)if(E[e].cap>=limit){  
  44.             int tmp = d[u]+E[e].time;  
  45.             if(d[E[e].v] > tmp){  
  46.                 d[E[e].v] = tmp;  
  47.                 if(!inq[E[e].v]){  
  48.                     inq[E[e].v] = true;  
  49.                     q.push(E[e].v);  
  50.                 }  
  51.             }  
  52.         }  
  53.     }  
  54.     return d[n];  
  55. }  
  56.   
  57. int main(){  
  58.     int T, u, v, c, d;  
  59.     scanf("%d",&T);  
  60.     while(T--){  
  61.         scanf("%d%d%d",&n,&m,&t);  
  62.         init();  
  63.         for(int i=0; i<m; ++i){  
  64.             scanf("%d%d%d%d",&u,&v,&c,&d);  
  65.             cap[i]=c;  
  66.             addEdge(u,v,c,d);  
  67.             addEdge(v,u,c,d);    //有一点没理解为什么用两条边,难道是因为是无向边。。。
  68.         }  
  69.         sort(cap, cap+m,greater<int>());  
  70.         // 二分求解  
  71.         int left=0, right=m-1, mid;  
  72.         while(left<right){  
  73.             mid = (left+right)>>1;   //这里需要注意,最好用位运算比较快
  74.             limit = cap[mid];  
  75.             int tmp=Dijkstra(1);  
  76.             if(tmp==INF || tmp>t){  
  77.                 left = mid+1;  
  78.             }  
  79.             else{  
  80.                 right=mid;  
  81.             }  
  82.         }  
  83.         printf("%d\n", cap[left]);  
  84.     }  
  85.     return 0;  
  86. }  
 ②最短路+SPFA+二分查找
  1. #include<iostream>  
  2. #include<algorithm>  
  3. #include<cstdio>  
  4. #include<cstring>  
  5. #include<queue>  
  6. using namespace std;  
  7.   
  8. #define MAXN 110010  
  9. #define INF 0x7FFFFFFF  
  10.   
  11. int cnt , n , m , t;  
  12. int first[MAXN] , next[MAXN];  
  13. int star[MAXN] , end[MAXN];  
  14. int value[MAXN] , Time[MAXN];  
  15. int dis_Time[MAXN];  
  16. int vis[MAXN];  
  17. queue<int>q;  
  18.   
  19. void init(){   
  20.     memset(first , -1 , sizeof(first));  
  21.     memset(next , -1 , sizeof(next));  
  22. }  
  23.   
  24. void SPFA(int s){  
  25.    memset(vis , 0 , sizeof(vis));  
  26.    for(int i = 2 ; i <= n ; i++)  
  27.       dis_Time[i] = INF;  
  28.    dis_Time[1] = 0;  
  29.    q.push(1);  
  30.    vis[1] = 1;  
  31.    while(!q.empty()){  
  32.       int  x = q.front();  
  33.       q.pop();  
  34.       vis[x] = 0;  
  35.       for(int  i = first[x] ; i != -1 ; i = next[i]){  
  36.          if(dis_Time[end[i]] > dis_Time[x] + Time[i] && s <= value[i]){/*这里加了一个边长都要大于s*/  
  37.             dis_Time[end[i]] = dis_Time[x] + Time[i];  
  38.             if(!vis[end[i]]){  
  39.                vis[end[i]] = 1;  
  40.                q.push(end[i]);  
  41.             }  
  42.          }  
  43.       }  
  44.    }  
  45. }  
  46.   
  47. int main(){  
  48.    scanf("%d" , &cnt);  
  49.    while(cnt--){  
  50.       scanf("%d%d%d" , &n , &m , &t);  
  51.       init();  
  52.   
  53.       for(int i = 0 ; i < m ; i++){  
  54.          scanf("%d%d%d%d" , &star[i] , &end[i] , &value[i] , &Time[i]);  
  55.          star[i+m] = end[i] , end[i+m] = star[i];  
  56.          value[i+m] = value[i] , Time[i+m] = Time[i];  
  57.   
  58.          next[i] = first[star[i]];  
  59.          first[star[i]] = i;  
  60.          next[i+m] = first[star[i+m]];  
  61.          first[star[i+m]] = i+m;  
  62.       }  
  63.       /*二分最短路*/  
  64.       int tmp_value[MAXN];  
  65.       memcpy(tmp_value , value , sizeof(tmp_value));  
  66.       sort(tmp_value , tmp_value+m);  
  67.         
  68.       int left , right , mid , ans;  
  69.       left = 0 , right = m-1;  
  70.       /*二分查找的形式*/  
  71.       while(left <= right){  
  72.           mid = (right+left)/2;  
  73.           SPFA(tmp_value[mid]);  
  74.           if(dis_Time[n] <= t)/*满足条件还要继续二分,因为不是最大*/  
  75.             ans = tmp_value[mid] , left = mid + 1;  
  76.           else  
  77.             right = mid - 1;  
  78.       }  
  79.       printf("%d\n" , ans);  
  80.    }  
  81.    return 0;  
  82. }  
0 0