HDU - 3696 Farm Game SPFA最长路

题意:有n种产品,每种产品有一定的价值和数量,
某些产品可以转换为另一种产品,有一定的转换率(转换中数量有损失)。
求最多能获得多少价值。
 
在转换过程中,转换率是要乘起来的,最后再乘上转换成的产品的价值,
如果这个价值比原来的大,就转换产品。
由于可以通过多种路径转换成另一种产品,所以用SPFA求最长路。
乘法通过log取对数转换为加法。
现在需要知道每个产品所能转换得到的最多价值,也就是求每个点到其他点最长路的最大值。
加一个附加点s,所有点连接到s,边权为log(p[i]),这样直接求每个点到s的最长路就可以知道最大值了。
这样需要n次SPFA,不过如果我们把图反向,求一次s开始的最长路,就可以知道所有点能转换的最大价值了。
最后再把这些值和以前的价值比较,得到每种产品的最大价值。
#include<cstdio>
#include<cstring>
#include<queue>
#include<cstring>
#include<cmath>

using namespace std;

const int MAXN=10010; 
const int MAXM=1000000;
const int INF=0x3f3f3f3f; 

struct	Edge
{ 
	int next;
	int	v; 
	double	cost; 
}edge[MAXM];

int tot;
double ans;
int head[MAXN];
double p[MAXN],w[MAXN];


void init()
{
	memset(head,-1,sizeof(head));
	tot=0;
	ans=0;
}

void addedge(int u,int v,double w) 
{ 
	edge[tot].v=v;
	edge[tot].cost=w;
	edge[tot].next=head[u];
	head[u]=tot++;
} 

bool vis[MAXN];
int cnt[MAXN];
double dist[MAXN]; 

bool SPFA(int start,int n) 
{ 
	memset(vis,false,sizeof(vis)); 
	memset(dist,0,sizeof(dist));
	vis[start]=true; 
	queue<int>que; 
	while(!que.empty())
		que.pop(); 
	que.push(start); 
	memset(cnt,0,sizeof(cnt)); 
	cnt[start]=1; 
	while(!que.empty()) 
	{ 
		int u=que.front(); 
		que.pop(); 
		vis[u]= false; 
		for(int i=head[u];i!=-1;i=edge[i].next) 
		{ 
			int v=edge[i].v; 
			if(dist[v]<dist[u]+edge[i].cost) 
			{ 
				dist[v]=dist[u]+edge[i].cost;
				if(!vis[v]) 
				{ 
					vis[v]=true; 
					que.push(v); 
					if(++cnt[v]>n)
						return false; 
				} 
			} 
		} 
	} 
	return	true; 
} 

int main()
{
	int n,k,m,a,b;
	double e;
	while(scanf("%d",&n),n)
	{
		init();
		for(int i=1;i<=n;i++)
		{
			scanf("%lf%lf",&p[i],&w[i]);
			addedge(0,i,log10(p[i]));
		}
		scanf("%d",&m);
		while(m--)
		{
			scanf("%d",&k);
			scanf("%d",&a);
			k--;
			while(k--)
			{
				scanf("%lf",&e);
				scanf("%d",&b);
				addedge(b,a,log10(e));
				a=b;
			}
		}
		SPFA(0,n);
		for(int i=1;i<=n;i++)
		{
			if(p[i]<pow(10.0,dist[i]))
				p[i]=pow(10.0,dist[i]);
			ans+=p[i]*w[i];
		}
		printf("%.2lf\n",ans);
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值