BZOJ 1706 usaco 2007 Nov relays 奶牛接力跑/POJ 3613 Cow Relays 倍增Floyd

73 篇文章 0 订阅
9 篇文章 0 订阅

题目大意:求恰好走k步从S到T的最短路。


思路:设f[p][i][j]为从i到j恰好走2^p步的最短路,DP方程十分简单:f[p][i][j] = min(f[p][i][j],f[p - 1][i][k] + f[p - 1][k][j]);

对总步数T进行二进制拆分,在T有1的位置上,假如这个位置为p,那么就用f[p][][]来更新答案g[][],最后得到的g[][]就是答案矩阵。

注意要离散化一下。。


CODE:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 210
using namespace std;
#define min(a,b) ((a) < (b) ? (a):(b))
#define max(a,b) ((a) > (b) ? (a):(b))
 
struct Complex{
    int x,y,len;
     
    void Read() {
        scanf("%d%d%d",&len,&x,&y);
    }
}edge[MAX];
 
pair<int,int *> xx[1010];
int cnt,t;
 
int T,edges,points,start,end;
int f[20][MAX][MAX],g[MAX][MAX],h[MAX][MAX];
 
int main()
{
    cin >> T >> edges >> start >> end;
    memset(g,0x3f,sizeof(g));
    memset(f,0x3f,sizeof(f));
    for(int i = 1; i <= edges; ++i) {
        edge[i].Read();
        xx[++cnt].first = edge[i].x,xx[cnt].second = &edge[i].x;
        xx[++cnt].first = edge[i].y,xx[cnt].second = &edge[i].y;
    }
    xx[++cnt].first = start,xx[cnt].second = &start;
    xx[++cnt].first = end,xx[cnt].second = &end;
    sort(xx + 1,xx + cnt + 1);
    for(int i = 1; i <= cnt; ++i) {
        if(i == 1 || xx[i].first != xx[i - 1].first)
            ++t;
        *xx[i].second = t;
    }
    for(int i = 1; i <= edges; ++i)
        f[0][edge[i].x][edge[i].y] = f[0][edge[i].y][edge[i].x] = min(f[0][edge[i].x][edge[i].y],edge[i].len);
    points = t;
    for(int i = 1; i <= points; ++i)
        g[i][i] = 0;
    int p = 0;
    while(T) {
        if(T&1) {
            memset(h,0x3f,sizeof(h));
            for(int k = 1; k <= points; ++k)
                for(int i = 1; i <= points; ++i)
                    for(int j = 1; j <= points; ++j)
                        h[i][j] = min(h[i][j],g[i][k] + f[p][k][j]);
            memcpy(g,h,sizeof(g));
        }
        T >>= 1;
        ++p;
        for(int k = 1; k <= points; ++k)
            for(int i = 1; i <= points; ++i)
                for(int j = 1; j <= points; ++j)
                    f[p][i][j] = min(f[p][i][j],f[p - 1][i][k] + f[p - 1][k][j]);
    }
    cout << g[start][end] << endl;
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值