POJ 3268 Silver Cow Party Dijkstra 单源最短路

POJ 3268 Silver Cow Party

博客搬新家,以后就是基本只在自己的独立博客进行更新,欢迎访问。http://zihengoi.cn

题目描述:

  题目描述:POJ 3268 Silver Cow Party

题目大意:

  有 N 个农场,在这些农场里有m条单向的路。每个农场出一个奶牛,在 X 农场聚会。问每个奶牛至少要花多久在往返的路上。

解题思路:

  题目说至少花多少时间在来回的路上,也就是说在求再来回路上用时最短的母牛的所用时间。显然可以将这个划分为两部分。

  • 每只牛从X农场回到自己农场的时间:这个很简单,直接对于X农场用 dijkstra 求到各点的最短距离即可。

    • 每只牛前往 X 农场所用时间:用到了一个技巧叫做,转置矩阵。之前我们求了每只牛回到自己农场的时间。现在只要把给的矩阵按照fm2[j][i]=fm1[i][j]转置,重新对X农场用 Dijkstra 求一次即可。
      • 最终要找的最短时间:找出的 d1[i]+d2[i] 的最小值即可。
          
      • 复杂度分析:

        时间复杂度 : O(n2)
        空间复杂度 : O(n2)

        AC代码:

        #include <cstdio>
        #include <cstring>
        #include <cmath>
        #include <queue>
        #include <iostream>
        
        using namespace std;
        const int maxn = 1010;
        const int INF = 0x3fffffff;
        int fm1[maxn][maxn],fm2[maxn][maxn];
        struct Heapnode{
            int d,u;
            bool operator < (const Heapnode& rhs) const{
                return d > rhs.d;
            }
        };
        
        struct Edge{
            int form,to,dist;
        };
        
        struct Diskstra{
            int n,m;
            vector<Edge> edges;
            vector<int> G[maxn];
            bool done[maxn];
            int d[maxn];
            int p[maxn];
        
            void init(int n){
                this->n = n;
                for(int i = 0; i < n; i++) G[i].clear();
                edges.clear();
            }
        
            void AddEdge(int from, int to,int dist){
                edges.push_back((Edge){from,to,dist});
                m = edges.size();
                G[from].push_back(m-1);
            }
        
            void dijkstra(int s){
                priority_queue<Heapnode>Q;
                for(int i = 0; i < n; i++)d[i] = INF;
                d[s] = 0;
                memset(done,0,sizeof(done));
                Q.push((Heapnode){0,s});
                while(!Q.empty()){
                    Heapnode x = Q.top();
                    Q.pop();
                    int u = x.u;
                    if(done[u]) continue;
                    done[u] = true;
                    for(int i = 0; i < G[u].size(); i++) {
                        Edge&e = edges[G[u][i]];
                        if(d[e.to] > d[u] + e.dist){
                            d[e.to] = d[u] + e.dist;
                            p[e.to] = G[u][i];
                            Q.push((Heapnode){d[e.to],e.to});
                        }
                    }
                }
            }
        };
        
        void trans(int n){
            for(int i = 0; i < n; i++)
                for(int j = 0; j < n; j++)
                    fm2[j][i] = fm1[i][j];
        }
        
        int main(){
            int x,n,m;
            while(scanf("%d%d%d",&n,&m,&x) != EOF){
                Diskstra ans1,ans2;
                ans1.n = ans2.n = n;
                ans1.m = ans2.m = m;
                ans1.init(n);
                ans2.init(n);
                memset(fm1,-1,sizeof(fm1));
                memset(fm2,-1,sizeof(fm2));
                for(int i = 0; i < m ;i++){
                    int from,to,dist;
                    scanf("%d%d%d",&from,&to,&dist);
                    fm1[--from][--to] = dist;
                }
                trans(n);
                for(int i = 0; i < n; i++)
                    for(int j = 0; j < n; j++){
                        if(fm1[i][j] > 0) ans1.AddEdge(i,j,fm1[i][j]);
                        if(fm2[i][j] > 0) ans2.AddEdge(i,j,fm2[i][j]);
                }
                x--;
                ans1.dijkstra(x);
                ans2.dijkstra(x);
                int ans = 0;
                for(int i = 0; i < n; i++){
                    if(ans1.d[i] + ans2.d[i] > ans) ans = ans1.d[i] + ans2.d[i];
                }
                printf("%d\n",ans);
            }
            return 0;
        }
        
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值