题意:
给定一个有向图,每个点有一个点权,给定起点,初始体力为1,经过一条边体力会变为原来的p倍,到达每个点时会得到点权乘上体力的价值,求规划一条路径使得价值和最大,输出保留1位小数
范围&性质:有向图可能存在环,\(1\le n\le 100,1\le m \le 10^3,0< p<1\)
分析:
n很小好像可以做,p固定可以直接倍增
\(dp[i][j][k]\)表示走\(2^i\)步,从j到达k时得到的价值最大,转移式为
\[dp[i][j][k]=max(dp[i-1][j][l]+dp[i-1][l][k]\times qpow(p,2^{i-1}))
\]
滚动数组可以消掉倍增那一维
代码:
#include<bits/stdc++.h>
using namespace std;
namespace zzc
{
const int maxn = 105;
const double eps = 1e-10;
int n,m,st;
double f[maxn][maxn],dp[maxn][maxn],ans,p,v[maxn];
void work()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%lf",&v[i]);
}
scanf("%d",&st);
scanf("%lf",&p);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(i==j) continue;
f[i][j]=-1e10;
}
}
for(int i=1,a,b;i<=m;i++)
{
scanf("%d%d",&a,&b);
f[a][b]=v[b]*p;
}
for(;p>=eps;p=p*p)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
dp[i][j]=-1e10;
}
}
for(int k=1;k<=n;k++)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
dp[i][j]=max(dp[i][j],f[i][k]+f[k][j]*p);
}
}
}
memcpy(f,dp,sizeof(dp));
}
ans=-1e5;
for(int i=1;i<=n;i++)
{
ans=max(ans,f[st][i]);
}
printf("%.1lf\n",ans+v[st]);
}
}
int main()
{
zzc::work();
return 0;
}