传送门biu~biu~
只需要考虑第一次购买的顺序,然后剩下需要买的都按最小价格买。设一个虚拟节点0,原价购买i物品就从0向i连边,u对v有优惠关系就从u向v连边。跑朱刘算法即可。
#include <bits/stdc++.h>
#define N 105
#define M 10005
#define inf 1e30
using namespace std;
int n,k,v,m,pre[N],id[N],vis[N],b[N];
double a[N],low[N],in[N],ans;
struct edge{
int u,v;double w;
edge(){}
edge(int u,int v,double w):u(u),v(v),w(w){}
}e[M];
void add(int u,int v,double w){e[m++]=edge(u,v,w);}
double zhuliu(int rt) {
double ret=0;
while(1){
for(int i=0;i<v;++i) in[i]=inf,id[i]=-1,vis[i]=-1;
for(int i=0;i<m;++i){
int u=e[i].u,v=e[i].v;double w=e[i].w;
if(w<in[v] && v!=u) pre[v]=u,in[v]=w;
}
in[rt]=0;pre[rt]=rt;
for(int i=0;i<v;++i){
if(in[i]==inf) return -1;
ret+=in[i];
}
int num=0;
for(int i=0;i<v;++i){
int u=i;
while(vis[u]==-1) vis[u]=i,u=pre[u];
if(vis[u]!=i || u==rt) continue;
for(int t=pre[u];t!=u;t=pre[t]) id[t]=num;
id[u]=num++;
}
if (num==0) break;
for(int i=0;i<v;++i) if(id[i]==-1) id[i]=num++;
for(int i=0;i<m;++i) e[i].w-=in[e[i].v],e[i].u=id[e[i].u],e[i].v=id[e[i].v];
v=num; rt=id[rt];
}
return ret;
}
int main(){
scanf("%d",&n);v=n+1;
for(int i=1;i<=n;++i){
scanf("%lf%d",&a[i],&b[i]),low[i]=a[i];
if(b[i]) add(0,i,a[i]);
else add(0,i,0);
}
scanf("%d",&k);
for(int i=1;i<=k;++i){
int u,v;double w;
scanf("%d%d%lf",&u,&v,&w);
if(b[u] && b[v]){
add(u,v,w);
low[v]=min(low[v],w);
}
}
ans=zhuliu(0);
for(int i=1;i<=n;++i) if(b[i]) ans+=low[i]*(b[i]-1);
printf("%.2lf",ans);
return 0;
}