P4308 [CTSC2011]幸福路径 倍增+Floyd

题意:

给定一个有向图,每个点有一个点权,给定起点,初始体力为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;
}
原文地址:https://www.cnblogs.com/youth518/p/13666804.html