题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=3696
思路:每种商品可以直接卖掉,也可以换购后卖掉。所以设点n+1,从该点向每个商品连边权值为log(p[i])(将乘法转换为加法,直接使用SPFA)表示直接卖掉的单位价值;对于可以换购的商品 i-->j,连 j--> i 权值为log(b[j])的边(反向建图,只需求一次最长路),表示单位 i 商品可以转换为b[j] 的 j 商品(求最长路时逐步累乘转换率)。求n+1点到各点的最长路,dist[i]即为单位i商品的最大价值,与 i 商品的数量相乘累加即可。
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#define debu
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=1e4+50;
struct Node
{
int v;
double w;
Node(int v=0,double w=0):v(v),w(w) {}
};
queue<int> q;
vector<Node> g[maxn];
double dist[maxn],b[maxn];
int v[maxn],n,m,k,a[maxn];
double val[maxn],have[maxn];
void solve(int s)
{
memset(v,0,sizeof(v));
while(!q.empty()) q.pop();
for(int i=0; i<=n+1; i++) dist[i]=-INF;
q.push(s),v[s]=0,dist[s]=0;
while(!q.empty())
{
int now=q.front();
q.pop(),v[now]=0;
for(int i=0; i<g[now].size(); i++)
{
int nt=g[now][i].v;
if(dist[nt]<dist[now]+g[now][i].w)
{
dist[nt]=dist[now]+g[now][i].w;
if(!v[nt])
{
v[nt]=1;
q.push(nt);
}
}
}
}
}
int main()
{
#ifdef debug
freopen("in.in","r",stdin);
#endif // debug
while(scanf("%d",&n)==1&&n)
{
for(int i=1; i<=n+1; i++) g[i].clear();
for(int i=1; i<=n; i++)
{
scanf("%lf%lf",&val[i],&have[i]);
g[n+1].push_back(Node(i,log10(val[i])));
}
scanf("%d",&m);
for(int i=1; i<=m; i++)
{
scanf("%d",&k);
scanf("%d",&a[0]);
for(int j=1; j<=k-1; j++)
scanf("%lf%d",&b[j],&a[j]);
for(int j=1; j<=k-1; j++)
{
//cout<<a[j]<<" "<<a[j-1]<<" "<<b[j]*val[a[j]]<<endl;
g[a[j]].push_back(Node(a[j-1],log10(b[j])));
}
}
/*for(int i=1;i<=n+1;i++)
{
for(int j=0;j<g[i].size();j++)
cout<<i<<" "<<g[i][j].v<<" "<<g[i][j].w<<endl;
}*/
solve(n+1);
double ans=0.0;
for(int i=1; i<=n; i++)
{
//cout<<dist[i]<<" "<<have[i]<<endl;
ans+=pow(10.0,dist[i])*have[i];
}
printf("%.2f\n",ans);
}
return 0;
}