• Graph


    题目:

    【问题描述】

    给你一个有向图,有 N 个点,标号为 0 到 N -1,图中的每条边有个权值,每次你经过一条边,它的权值将被记入你的得分,如果同样的边被经过多次,它的权值每次都将被记入总分,权值为-499 到 499之间的整数,图中没有自环,现在你要从点 0 到点 1,这项任务必须在时限 T 或 T 之前完成,时间以秒记,每一秒你一定要走 S 步(不多不少),一步的含义是指从当前所在的点 U 沿着某条边( U , V )到达点 V ,若S>1的话,再沿着点V往(V,X)到达点X。你的目标就是完成任务并且得到尽量多的分数。

    【输入格式】

    第一行一个整数 N 表示该有向图的点数。接下来 N 行,每行有 N 个整数,第 i 行第 j 个数描述了点 i -1 到点 j- 1 之间的边的关系,如果是 0 ,表示它们之间没有边,否则这个数就是 i- > j 这条边的边权,保证第 i 行第 i 个数为 0。最后一行两个整数 S , T ,意义如题目所述。

    【输出格式】

    仅输出一行,如果不能完成,输出 IMPOSSIBLE,否则输出能够获得的最大分数。

    【输入样例】

    2

    0 1

    1 0

    3 2

    【输出样例】

    3

    【数据范围】

    30%的数据,1≤ N , S , T ≤10。

    100%的数据,1≤ N ≤50,1≤ S ≤100,1≤ T ≤109 。

    题解:用f[i][j][t]表示从i到j,走t次的最大值

    矩阵更新,预处理每两个点走一次的最大值

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const LL inf=0x3fffffffffffffff;
    int n,S,T;
    LL Ans;
    struct Ma
    {
        LL val[51][51];
        void clear()
         {
            for (int i=0;i<n;i++)
             for (int j=0;j<n;j++)val[i][j]=-inf;
            for (int i=0;i<n;i++) val[i][i]=0;
         }
        void write()
         {
            for (int i=0;i<n;i++)
             {
                for (int j=0;j<n;j++)printf("%lld ",val[i][j]);
                puts("");
             }
         }
    }M1,M2,M3,M4;
    Ma times(Ma a,Ma b)
    {
        Ma c;
        for (int i=0;i<n;i++)
         for (int j=0;j<n;j++)
          {
            c.val[i][j] = -inf;
            for (int k=0;k<n;k++)
             {
                if (a.val[i][k]==-inf||b.val[k][j]==-inf)
                 continue;
                c.val[i][j]=max(c.val[i][j],
                a.val[i][k]+b.val[k][j]);
             }
         }
        return c;
    }
    Ma Pow(Ma a,int b)
    {
        Ma Ans;
        Ans.clear();
        for (;b;b>>=1,a=times(a,a))
         if (b&1) Ans=times(Ans,a);
        return Ans;
    }
    void solve()
    {
        M3=Pow(M2,T-2*n);
        Ans=max(Ans,M3.val[0][1]);
        for (int i=T-2*n+1;i<=T;i++)
         {
            M3=times(M3,M2);
            Ans=max(Ans,M3.val[0][1]);
         }
    }
    int main()
    {
        freopen("graph.in","r",stdin);
        freopen("graph.out","w",stdout);
        scanf("%d",&n);
        for (int i=0;i<n;i++)
         for (int j=0;j<n;j++)
          {
            scanf("%lld",&M1.val[i][j]);
            if (M1.val[i][j]==0)M1.val[i][j]=-inf;
          }
        scanf("%d%d",&S,&T);
        M2=Pow(M1,S);    
        Ans=-inf;
        M4.clear();
        for (int i=1;i<=min(T,2*n);i++)
         {
            M4=times(M4,M2);
            Ans=max(Ans,M4.val[0][1]);
         }
        if (T>=2*n+1) solve();
        if (Ans==-inf) puts("IMPOSSIBLE");
        else printf("%lld
    ",Ans);
        return 0;
    }
  • 相关阅读:
    form表单重置、清空方法记录
    window location assign的使用
    简单易用的拾色器推荐
    display属性常用的四个值:block、inline、inline-block、none
    idea如何配置外部电脑访问本地项目
    Unity 2D相机公式换算(从其他博客上抄的)
    关于游戏逻辑模式的观点----谁调用谁
    Unity 角色场景传送功能
    Unity关于方法事件生命周期官方文档
    关于Unity物理事件的执行顺序的最新理解
  • 原文地址:https://www.cnblogs.com/xuanyiming/p/7506527.html
Copyright © 2020-2023  润新知