P3008 [USACO11JAN]道路和飞机Roads and Planes

 

思路1:SLF优化spfa水过 

#include <bits/stdc++.h>
using namespace std;
const int maxn = 25005;
const int maxm = 5000005;
const int inf = 0x3f3f3f3f;
int he[maxn],ver[maxm],ne[maxm],tot,cost[maxm];
void add( int x,int y,int z ){
    ver[++tot] = y;
    ne[tot] = he[x];
    he[x] = tot;
    cost[tot] = z;
}
int n,d[maxn],vis[maxn];
deque<int> que;
void spfa(int s){
    memset( d,0x3f,sizeof(int)*(n+1) );
    memset( vis,0,sizeof(int)*(n+1) );
    d[s] = 0;vis[s] = 1;
    que.push_back(s);
    while(que.size()){
        int x = que.front();
        vis[x] = 0;
        que.pop_front();
        for( int cure = he[x];cure;cure = ne[cure] ){
            int y = ver[cure];
            if( d[y] > d[x] + cost[cure] ){
                d[y] = d[x] + cost[cure];
                if( !vis[y] ) {
                    if(que.size()&&  d[y] < d[que.front()] )que.push_front(y);
                    else que.push_back(y);
                    vis[y] = 1;
                }
            }
        }
    }
}
int main(){
    int r,p,s,x,y,z;
    scanf("%d%d%d%d",&n,&r,&p,&s);
    for( int i = 1;i <= r;i++ ){
        scanf("%d%d%d",&x,&y,&z);
        add( x,y,z );add( y,x,z );
    }
    for( int i = 1;i <= p;i++ ){
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z);
    }
    spfa(s);
    for( int i = 1;i <= n;i++ ){
        if( d[i] == inf ){
            puts("NO PATH");
        }
        else printf("%d\n",d[i]);
    }
    return 0;
}

思路2:拓扑排序 + dijstra

#include <bits/stdc++.h>
using namespace std;
const int maxn = 250005;
const int maxm = 5000005;
const int inf = 0x7f7f7f7f;
int n,r,p,s;
int he[maxn],ver[maxm],ne[maxm],cost[maxm],tot;
int he2[maxn],ver2[maxm],ne2[maxm],tot2;
void add2( int x,int y ){
    ver2[++tot2] = y;
    ne2[tot2] = he2[x];
    he2[x] = tot2;
}
void add( int x,int y,int z ){
    ver[++tot] = y;
    ne[tot] = he[x];
    he[x] = tot;
    cost[tot] = z;
}
vector<int> ve[maxn];
int du[maxn],vis[maxn],c[maxn];
void dfs( int x,int color ){
    c[x] = color;
    for( int cure = he[x];cure;cure = ne[cure] ){
        int y = ver[cure];
        if(c[y]) continue;
        dfs(y,color);
    }
}
int d[maxn];
void init( int s ){
    memset( d,0x7f,sizeof(int)*(n+1) );
    d[s] = 0;
}
typedef pair<int,int> pii;
priority_queue<pii,vector<pii>,greater<pii>> que;
void dijkstra(int color){
    for( int i = 0;i < ve[color].size();i++ ){
        que.push( pii( d[ve[color][i]],ve[color][i] ) );
    }
    while(que.size()){
        int x = que.top().second;
        que.pop();
        for( int cure = he[x];cure;cure = ne[cure] ){
            int y = ver[cure];
            if( d[y] > d[x] + cost[cure] ){
                d[y] = d[x] + cost[cure];
                if( c[y] == c[x] )
                que.push( pii(d[y],y) );
            }
        }
    }
}
queue<int> Q;
int main(){
    scanf("%d%d%d%d",&n,&r,&p,&s);
    init(s);
    int x,y,z,color = 0;
    for( int i = 1;i <= r;i++ ){
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z);add(y,x,z);
    }
    for( int i = 1;i <= n;i++ ){
        if( !c[i] )
        dfs(i,++color);
    }
    memset( vis,0,sizeof(int)*(n+1) );
    for( int i = 1;i <= n;i++ ){
        ve[ c[i] ].push_back(i);
    }
    for( int i = 1;i <= p;i++ ){
        scanf("%d%d%d",&x,&y,&z);
        add( x,y,z );
        add2( c[x],c[y] );
        du[c[y]]++;
    }
    for( int i = 1; i <= color;i++ ){
        if( !du[i] ) {
            Q.push(i);
            dijkstra(i);
        }
    }
    while(Q.size()){
        int x = Q.front();
        Q.pop();
        for( int cure = he2[x];cure;cure = ne2[cure] ){
            int y = ver2[cure];
            du[y]--;
            if(!du[y]){
                Q.push(y);
                dijkstra(y);
            }
        }
    }
    for( int i = 1; i <= n;i++ ){
        if( d[i]>=0x3f3f3f3f ) puts("NO PATH");
        else printf("%d\n",d[i]);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,这是一道经典的单调栈问题。题目描述如下: 有 $n$ 个湖,第 $i$ 个湖有一个高度 $h_i$。现在要在这些湖之间挖一些沟渠,使得相邻的湖之间的高度差不超过 $d$。请问最少需要挖多少个沟渠。 这是一道单调栈的典型应用题。我们可以从左到右遍历湖的高度,同时使用一个单调栈来维护之前所有湖的高度。具体来说,我们维护一个单调递增的栈,栈中存储的是湖的下标。假设当前遍历到第 $i$ 个湖,我们需要在之前的湖中找到一个高度最接近 $h_i$ 且高度不超过 $h_i-d$ 的湖,然后从这个湖到第 $i$ 个湖之间挖一条沟渠。具体的实现可以参考下面的代码: ```c++ #include <cstdio> #include <stack> using namespace std; const int N = 100010; int n, d; int h[N]; stack<int> stk; int main() { scanf("%d%d", &n, &d); for (int i = 1; i <= n; i++) scanf("%d", &h[i]); int ans = 0; for (int i = 1; i <= n; i++) { while (!stk.empty() && h[stk.top()] <= h[i] - d) stk.pop(); if (!stk.empty()) ans++; stk.push(i); } printf("%d\n", ans); return 0; } ``` 这里的关键在于,当我们遍历到第 $i$ 个湖时,所有比 $h_i-d$ 小的湖都可以被舍弃,因为它们不可能成为第 $i$ 个湖的前驱。因此,我们可以不断地从栈顶弹出比 $h_i-d$ 小的湖,直到栈顶的湖高度大于 $h_i-d$,然后将 $i$ 入栈。这样,栈中存储的就是当前 $h_i$ 左边所有高度不超过 $h_i-d$ 的湖,栈顶元素就是最靠近 $h_i$ 且高度不超过 $h_i-d$ 的湖。如果栈不为空,说明找到了一个前驱湖,答案加一。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值