题目:click~
SPFA最长路,思路如下:
先对题目中给出的每条边建边,权值为转化率;增加一个终点S,每个节点到S建边,权值为该物品的单价。
假设X物品最终转化为了Y物品,那么转化之后得到的钱就是 W[x]*转化率1*转化率2*转化率3*转化率4*.....*P[Y]
现在我们关注 转化率1*转化率2*转化率3*转化率4*.....*P[Y] 这个式子,实际上就是求这个式子的最大值。
怎么求?事实上就是节点X到节点S的最长路。如果这样去求,那么需要N次SPFA;所以我们需要反向建边,从S出发开始求最长路。最终比较一下转换后的价格和之前的价格哪个大,就用哪个。.
#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
#include <cmath>
#include <vector>
#include <cstring>
#include <queue>
using namespace std;
const double INF=2100000000.0;
const int maxn = 50010;
int head[maxn],nxt[maxn],to[maxn],e;
double w[maxn],p[maxn],cost[maxn];
int a[maxn];
double b[maxn];
void add(int u,int v,double t)
{
to[e] = v; nxt[e] = head[u];cost[e] = t; head[u] = e++;
}
void init(int n)
{
e = 2;
memset(head,0,sizeof(head));
}
bool vis[maxn];
double dist[maxn];
void SPFA(int s)
{
memset(vis,0,sizeof(vis));
memset(dist,-INF,sizeof(dist));
queue<int> Q;
while(!Q.empty()) Q.pop();
dist[s] = 1;
Q.push(s);vis[s] = true;
while(!Q.empty())
{
int u = Q.front();Q.pop();
vis[u] = false;
for(int e = head[u];e;e=nxt[e])
{
int v = to[e];
if(dist[u]*cost[e]>dist[v])
{
if(!vis[v]) Q.push(v);
dist[v] =dist[u]*cost[e];
vis[v] = true;
}
}
}
}
int main()
{
int n,m;
while(cin >> n&&n)
{
init(n);
for(int i=1;i<=n;i++)
scanf("%lf %lf",&w[i],&p[i]);
for(int i=1;i<=n;i++)
{
add(n+1,i,w[i]);
}
scanf("%d",&m);
for(int i=0;i<m;i++)
{
int k;
scanf("%d",&k);
scanf("%d",&a[0]);
for(int j=1;j<k;j++)
{
scanf("%lf %d",&b[j],&a[j]);
add(a[j],a[j-1],b[j]);
}
}
int s = n+1;
SPFA(s);
double ans = 0;
for(int i=1;i<=n;i++)
{
ans += p[i]*max(w[i],dist[i]);//printf("%.2f\n",ans);
}
printf("%.2f\n",ans);
}
return 0;
}