题意:有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);
}
}