[矩阵乘法][最短路]无奈的学长

Problem A: 无奈的学长

Time Limit: 1 Sec   Memory Limit: 128 MB
Submit: 26   Solved: 3
[ Submit][ Status][ Web Board]

Description

众所周知,YONG学长是一个有妹子的汉子,可是众所不周知,有妹子的汉子给学弟出一道题做也会经常被打断。
“喂,亲爱的,我在A区,你在学院给我采几朵花,然后拿给我看好吗?”
“可是...我在宿舍...给学弟们出题...”
“立马的...”
“...”
“我有一个要求,采花的时候,每次经过一条路,只能在这条路上采一朵最好的给我。要快哦~”
“...”
逆来顺受&悲愤交加的YONG学长,为了能挤出更多时间出题,只好手工计算出一条距离最短的路径。
还好计算过程只花了短短半个小时,后来他兴高采烈的去见了学姐,卒。
假若时光能够倒流,聪明善良的你是否愿意帮助YONG学长找到这个距离最短的路径,输出路径长度。
hint:
任意两个建筑物之间都是一条路。
假设每条路上有无数多花。
假设YONG学长每次都能在走完一条路后找到最好的花并采下。
题目保证数据合理。
...
不要在意这些细节。

Input

多case。
每个case第一行输入一个数字N(1 <= N <= 30),代表学院一共有多少个地点(地点从1到N标号)。
下面N行,每行两个数字x,y,(0 < x < 30,0 < y < 30)代表该地点的物理坐标。
最后一行两个三数字,S和E,K(1 <= K <= 10000000)分别代表YONG学长和学姐在电话刚刚打通时候的地点标号,以及学姐要得到的花数目。

Output

每个输出独占一行,结果保留小数点后两位。

Sample Input

10 01 1 020 00 11 1 2

Sample Output

0.002.00

HINT


floyd算法的方程是f[i,j] = min(f[i,k]+f[k,j])k∈[1,n]

将矩阵乘法的算法c[i,j] = ∑(a[i,k]*b[k,j])稍微修改一下就得到任意i,j间经过一次转移的最短路。

由于不能在原地停留,所以原矩阵的主对角线为正无穷。

矩阵乘法用快速幂实现。

时间复杂度为O(n^3lgK)


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
 
const int maxn = 40;
/
int n;
 
struct matrix
{
    double m[maxn][maxn];
    void operator*=(matrix m2)
    {
        matrix rs;
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++)
                rs.m[i][j] = 1e18;
 
        for (int i=1;i<=n;i++)
        {
            for (int j=1;j<=n;j++)
            {
                for (int k=1;k<=n;k++)
                {
                    rs.m[i][j] = min(rs.m[i][j],m[i][k]+m2.m[k][j]);
                }
            }
        }
         
        *this = rs;
        //return rs;
    }
    void clear(){memset(m,0,sizeof m);for(int i=1;i<=n;i++)m[i][i]=1e18;}
    matrix(){clear();}
    matrix(const matrix& m2)
    {
        clear();
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++)
                m[i][j] = m2.m[i][j];
    }
    void operator=(const matrix& m2)
    {
        clear();
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++)
                m[i][j] = m2.m[i][j];
    }
};
//matrix a;
matrix map;
/
 
matrix kp(int k)
{
    matrix ans = map;
    matrix tmp = map;
    while (k)
    {
        if (k&1){ans*=tmp;}
        tmp *= tmp;
        k >>= 1;
    }
    return ans;
}
 
int x[maxn];
int y[maxn];
int main()
{
    while (scanf("%d",&n) != EOF)
    {
        for (int i=1;i<=n;i++)
            scanf("%d%d",x+i,y+i);
        map.clear();
        for (int i=1;i<=n;i++)
        {
            for (int j=i+1;j<=n;j++)
            {
                map.m[i][j] = map.m[j][i] = sqrt(double(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
            }
        }
 
        int s,e,k;
        scanf("%d%d%d",&s,&e,&k);
        if (n == 1)
        {
            printf("0.00\n");
            continue;
        }
        if (k <= 1)
        {
            printf("%.2f\n",map.m[s][e]);
            continue;
        }
 
        matrix ans = kp(k-1);
 
        printf("%.2f\n",ans.m[s][e]);
    }
    return 0;
}
/**************************************************************
    Problem: 1259
    User: wuyihao
    Language: C++
    Result: Accepted
    Time:3 ms
    Memory:1084 kb
****************************************************************/


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值