USACO January Contest Gold Time is Mooney 题解

题意

给出一个有向图,走到每个节点有 (m_i) 的收益,每一条边要走一天,走 (T) 天的花费是 (Ccdot T^2),求从节点 (1) 开始并且在节点 (1) 结束的旅行的最大利润?(利润等于收益减去花费)

另外也可以不进行旅行,即零利润。

题解

注意到收益是线性增长,而花费是指数级增长,因此花费将逐渐超过收益。

以收益均为 (1000)(C=1) 为例,即收益最大化,成本最小化,运行时间最长。
可见 (T=sqrt{1000}) 为最大值,可视为常数
那么这题的时间复杂度就是 (O(nm)) 了,在有利益的情况下拓展即可。

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
const int MAXN=1000+5;
struct Edge{int u,v,next;};
long long dp[MAXN*2][MAXN];int n,m,p,c[MAXN],cnt,head[MAXN];Edge edge[MAXN*2],tmp[MAXN*2];
bool comp(Edge a,Edge b) {return c[a.v]<c[b.v];}
void AddEdge(int u,int v)
{
//	printf("Add %d %d
",u,v);
	edge[++cnt].u=u;edge[cnt].v=v;edge[cnt].next=head[u];head[u]=cnt;
}
int main()
{
	freopen("time.in","r",stdin);
	freopen("time.out","w",stdout);
	scanf("%d %d %d",&n,&m,&p);
	int cmax=0;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&c[i]);
		cmax=std::max(cmax,c[i]);
	}
	for(int i=1;i<=m;i++)
		scanf("%d %d",&tmp[i].u,&tmp[i].v);
	std::sort(tmp+1,tmp+m+1,comp);
	for(int i=1;i<=m;i++)
		AddEdge(tmp[i].u,tmp[i].v);
	memset(dp,-0x3f3f3f,sizeof(dp));
	dp[0][1]=0;
	int i=0;bool moved=1;
	while(moved)
	{
		moved=0;
		int addcost=p*((i+1)*(i+1)-i*i);
		if(addcost>cmax) break;
		for(int j=1;j<=n;j++)
			if(dp[i][j]>=0)
				for(int k=head[j];k;k=edge[k].next)
				{
					//if(addcost<=c[edge[k].v])
					{
						//printf("Day %d From %d to %d, New: %lld
",i,j,edge[k].v,std::max(dp[i+1][k],dp[i][j]+c[edge[k].v]-addcost));
						dp[i+1][edge[k].v]=std::max(dp[i+1][edge[k].v],dp[i][j]+c[edge[k].v]-addcost);
						moved=1;
					}
				}
		i++;
	}
	long long ans=0;
	for(int p=1;p<=i;p++)
		ans=std::max(ans,dp[p][1]);
	printf("%lld
",ans);
	return 0;
}
无特别声明的情况下,本文为原创文章,允许转载,采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
在声明禁止转载的情况下,请勿转载;若本文章为转载的文章,版权归原作者所有。
如果您觉得本文写得好,请点击下方的推荐按钮~若您有任何建议和指正,请在下方留言,对于您的指正将不胜感激。
原文地址:https://www.cnblogs.com/ksyx/p/12313858.html