题目:

【问题描述】

给你一个有向图,有 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\n",Ans);
    return 0;
}

 

posted on 2017-09-11 19:27  宣毅鸣  阅读(260)  评论(0编辑  收藏  举报