kuangbin带你飞专题四最短路

POJ - 3268 Silver Cow Party

题意

求所有点到终点的最短路和终点到所有点的最短路
的累加和

思路

在有向图中, 求所有点到某点的最短距离, 建立反向图跑单源最短路即可

代码

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>

using namespace std;

const int N = 1010;

int g1[N][N];
int g2[N][N];
int dist1[N];
int dist2[N];
int n, m, p;
bool st[N];

void dijkstra(int g[N][N], int dist[N]) {
    memset(st, false, sizeof st);
    dist[p] = 0;
    for(int i = 0; i < n - 1; i ++) {
        int t = -1;
        for(int j = 1; j <= n; j ++) {
            if(!st[j] && (t == -1 || dist[t] > dist[j]))
                t = j;
        }
        st[t] = true;

        for(int j = 1; j <= n; j ++) {
            dist[j] = min(dist[j], dist[t] + g[t][j]);
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);

    cin >> n >> m >> p;
    memset(g1, 0x3f, sizeof g1);
    memset(g2, 0x3f, sizeof g2);
    while(m --) {
        int a, b, c;
        cin >> a >> b >> c;
        g1[a][b] = min(g1[a][b], c);
        g2[b][a] = min(g2[b][a], c);
    }
    memset(dist1, 0x3f, sizeof dist1);
    memset(dist2, 0x3f, sizeof dist2);
    dijkstra(g1, dist1);
    dijkstra(g2, dist2);

    int ans = 0;
    for(int i = 1; i <= n; i ++) {
        if(i != p && dist1[i] != 0x3f3f3f3f && dist2[i] != 0x3f3f3f3f)  {
            ans = max(ans, dist1[i] + dist2[i]);
        }
    }

    cout << ans << endl;

    return 0;
}

POJ - 1062 昂贵的聘礼

思路

虚拟源点建图 + 最短路

代码

#include<cstring>
#include<algorithm>
#include<iostream>

using namespace std;

const int N = 110, INF = 0x3f3f3f3f;

int w[N][N];
int level[N];
int n, m;
bool st[N];
int dist[N];

int dijkstra(int l, int r) {
    memset(dist, 0x3f, sizeof dist);
    memset(st, false, sizeof st);
    dist[0] = 0;

    for(int i = 1; i <= n; i ++) {
        int t = -1;
        for(int j = 0; j <= n; j ++) {
            if(!st[j] && (t == -1 || dist[t] > dist[j]))
                t = j;
        }

        st[t] = true;

        for(int j = 1; j <= n; j ++) {
            if(level[j] >= l && level[j] <= r) {
                dist[j] = min(dist[j], dist[t] + w[t][j]);
            }
        }
    }

    return dist[1];
}

int main() {
    cin >> m >> n;
    memset(w, 0x3f, sizeof w);
    for(int i = 0; i <= n; i ++)
        w[i][i] = 0;
    for(int i = 1; i <= n; i ++) {
        int price, cnt;
        cin >> price >> level[i] >> cnt;
        w[0][i] = min(w[0][i], price);
        while(cnt --) {
            int id, cost;
            cin >> id >> cost;
            w[id][i] = min(w[id][i], cost);
        }
    }

    int res = INF;
    for(int i = level[1] - m; i <= level[1]; i ++) {
        res = min(res, dijkstra(i, i + m));
    }

    cout << res << endl;

    return 0;
}

POJ2253 Frogger

题意

找出所有路径中最大边是最小的这个路径, 输出这个路径的最大边。

思路

数据小, floyd求解
f [ i ] [ j ] = m i n ( f [ i ] [ j ] , m a x ( f [ i ] [ k ] , f [ k ] [ j ] ) ) f[i][j] = min(f[i][j], max(f[i][k], f[k][j])) f[i][j]=min(f[i][j],max(f[i][k],f[k][j]))

代码

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#define sd(x) scanf("%d", &x)
#define rep(i, a, b) for(int i = a; i <= b; i ++)

using namespace std;

const int N = 205;

double g[N][N];
int n, x[N], y[N], time = 0;

void floyd() {
    int i, j, k;
    rep(i, 1, n)
        rep(j, i + 1, n) {
            g[i][j] = g[j][i] = sqrt(double(x[i] - x[j])*(x[i] - x[j]) + double(y[i] - y[j])*(y[i] - y[j]));
        }
    rep(k, 1, n)
        rep(i, 1, n)
            rep(j, 1, n){
                g[i][j] = min(g[i][j], max(g[i][k], g[k][j]));
            }
}
int main() {
    while(~scanf("%d", &n) && n) {
        time ++;
        for(int i = 1; i <= n; i ++)
            cin >>x[i] >> y[i];
        floyd();
        printf("Scenario #%d\nFrog Distance = %.3f\n\n", time, g[1][2]);
    }
    return 0;
}

POJ - 1797 Heavy Transportation

题意

与上题类似,正好相反
找出最小边是最大的路径,输出最小边

思路

这里用djkstra, 其他也行
dist[] 保存路径中最大的 最小边
d i s t [ j ] = m a x ( d i s t [ j ] , m i n ( d i s t [ v e r ] , g [ v e r ] [ j ] ) dist[j] = max(dist[j], min(dist[ver], g[ver][j]) dist[j]=max(dist[j],min(dist[ver],g[ver][j])

代码

#include<iostream>
#include<cstring>
#include<algorithm>
#define sd(x) scanf("%d", &x)
#define rep(i, a, b) for(int i = a; i <= b; i ++)
#include<queue>

using namespace std;

typedef pair<int, int> PII;
const int N = 1010;

int g[N][N];
int n, m;
int dist[N];
bool st[N];

void dijkstra() {
    priority_queue<PII> q;
    memset(dist, -0x3f, sizeof dist);
    memset(st, false, sizeof st);

    dist[1] = 0x3f3f3f3f;
    q.push({dist[1], 1});

    while(q.size()) {
        PII t = q.top(); q.pop();
        int ver = t.second;
        if(st[ver]) continue;
        st[ver] = true;

        for(int j = 1; j <= n; j ++) {
            if(g[ver][j] && !st[j])
                dist[j] = max(dist[j], min(dist[ver], g[ver][j]));
        }
    }

}


int main() {
    int T, id = 0;
    sd(T);
    while(T --){
        memset(g, 0, sizeof g);
        int n, m;
        sd(n), sd(m);
        while(m --) {
            int a, b, c;
            sd(a), sd(b), sd(c);
            g[a][b] = g[b][a] = c;
        }

        dijkstra();

        printf("Scenario #1:\n%d\n\n", ++id, dist[n]);
    }
}

POJ - 3660 Cow Contest

题意

找出确定排名的牛的个数
确定排名的条件,比自己小的 + 比自己大的 == n - 1

思路

传递闭包

代码

#include<iostream>
#include<cstring>
#include<algorithm>
#define sd(x) scanf("%d", &x)
#define rep(i, a, b) for(int i = a; i <= b; i ++)

using namespace std;

const int N = 110;
int g[N][N];
int n, m;

void floyd() {
    rep(k, 1, n)
        rep(i, 1, n)
            rep(j ,1, n) {
                g[i][j] |= g[i][k] & g[k][j];
            }
}

int main() {
    cin >> n >> m;
    while(m --) {
        int a, b;
        cin >> a >> b;
        g[a][b] = 1;
    }

    floyd();

    int ans = 0;
    for(int i = 1; i <= n; i ++) {
        int cnt = 0;
        for(int j = 1; j <= n; j ++) {
            if(g[i][j] || g[j][i]) cnt ++;
        }
        if(cnt == n - 1) ans ++;
    }

    cout << ans << endl;
}

HDU - 4725 The Shortest Path in Nya Graph

思路

非常妙的建图
把某层当成虚拟的点编号N+i,防止重复,
它到达它那层的所有点的距离是0
而某一层的点 到自己的上下层虚拟点 的距离是C

参考: 大佬题解

代码

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
const int maxn=2e5+10;
struct Node
{
    int to,w;
    Mode() {}
    Node(int to,int w):to(to),w(w) {}
};
vector<Node> vv[maxn];//用vector表示邻接表
int N,M,C;
int layer[maxn],islayer[maxn];//layer记录第i点所在的层数,islayer记录该层是否有点
int vis[maxn];
int dist[maxn];
struct cmp
{
    bool operator()(int a,int b)
    {
        return dist[a]>dist[b];
    }
};
void Dijkstra()
{
    priority_queue<int,vector<int>,cmp> pq;
    fill(dist,dist+maxn,INF);
    fill(vis,vis+maxn,0);
    dist[1]=0;
    pq.push(1);
    while(!pq.empty())
    {
 
        int u=pq.top();
        pq.pop();
        if(vis[u])
            continue;
        vis[u]=1;
        for(int i=0; i<vv[u].size(); i++)
        {
            int v=vv[u][i].to;
            int w=vv[u][i].w;
            if(dist[v]>dist[u]+w)
            {
                dist[v]=dist[u]+w;
                pq.push(v);
            }
        }
    }
}
int main()
{
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T,cas=0;
    cin>>T;
    while(T--)
    {
        memset(layer,0,sizeof(layer));
        memset(islayer,0,sizeof(islayer));
        memset(vv,0,sizeof(vv));
        cin>>N>>M>>C;
        //增点建图
        for(int i=1; i<=N; i++)//为每层分配一个点,并把它与所在该层的点相连接
        {
            cin>>layer[i];
            islayer[layer[i]]=1;
        }
        for(int i=1; i<=N; i++)//给每个点建边
        {
           vv[layer[i]+N].push_back(Node(i,0));
           if(islayer[layer[i]-1])//判断上一层的点是否存在,若存在连接
           {
               vv[i].push_back(Node(layer[i]-1+N,C));
           }
           if(islayer[layer[i]+1])//判断下一层的点是否存在,若存在连接
           {
               vv[i].push_back(Node(layer[i]+1+N,C));
           }
        }
        //插入M条边
        for(int i=1; i<=M; i++)
        {
            int u,v,w;
            cin>>u>>v>>w;
            vv[u].push_back(Node(v,w));
            vv[v].push_back(Node(u,w));
        }
 
        Dijkstra();
        if(dist[N]!=INF)
            cout<<"Case #"<<++cas<<": "<<dist[N]<<endl;
        else
            cout<<"Case #"<<++cas<<": -1"<<endl;
    }
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值