传送门
解析:
显然我们只需要考虑所有堡垒第一次攻打时候的花费,因为在所有堡垒攻打一遍之后,剩下的只需要一直用最小花费攻打就行了。
删去不用攻打的点,然后建立虚点,向所有点连边,权值为该点第一次攻打的花费。
剩下的边该连的就连上就行了。
然后以这个虚点为根求最小树形图就行了。
注意题目中有一个条件:保证攻打 u u u导致的 v v v的权值的改变一定比原来 v v v的权值小,如果去掉这个条件,就不能用最小树形图做了,读者可以想一想为什么。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<20|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
re char c;
while(!isdigit(c=gc()));re int num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
inline double getdb(){
re char c;
while(!isdigit(c=gc()));re double x=c^48;
while(isdigit(c=gc()))x=x*10+(c^48);
if(c!='.')return x;
re double y=1;
while(isdigit(c=gc()))x+=(y/=10)*(c^48);
return x;
}
}
using namespace IO;
using std::cout;
using std::cerr;
cs int N=52,M=1e4+4;
int n,m;
int u[M],v[M];
double w[M];
int id[N],pre[N],vis[N];
double in[N];
inline double DMST(int rt){
double ans=0;
while(true){
for(int re i=1;i<=n;++i)in[i]=1e20;
for(int re i=1;i<=m;++i)
if(u[i]!=v[i]&&w[i]<in[v[i]])
in[v[i]]=w[i],pre[v[i]]=u[i];
int cnt=0;
memset(vis+1,0,sizeof(int)*n);
memset(id+1,0,sizeof(int)*n);
for(int re i=1;i<=n;++i)if(i!=rt){
ans+=in[i];
int v=i;
while(vis[v]!=i&&!id[v]&&v!=rt){
vis[v]=i;
v=pre[v];
}
if(!id[v]&&v!=rt){
id[v]=++cnt;
for(int re u=pre[v];u!=v;u=pre[u])id[u]=cnt;
}
}
if(cnt==0)return ans;
for(int re i=1;i<=n;++i)
if(!id[i])id[i]=++cnt;
for(int re i=1;i<=m;++i){
int u=::u[i],v=::v[i];
::u[i]=id[u],::v[i]=id[v];
if(id[u]!=id[v])w[i]-=in[v];
}
rt=id[rt];
n=cnt;
}
}
double mn[N],ans;
int b[N];
int label[N];
signed main(){
n=getint();
for(int re i=1;i<=n;++i){
double w=getdb();int nn=getint();
if(nn){
v[++m]=m;
label[i]=m;
mn[m]=::w[m]=w;
b[m]=nn;
}
}
n=m+1;
for(int re i=1;i<n;++i)u[i]=n;
int nowm=getint();
while(nowm--){
int x=label[getint()],y=label[getint()];double t=getdb();
if(!x||!y||x==y)continue;
u[++m]=x;v[m]=y;w[m]=t;
mn[y]=std::min(mn[y],w[m]);
}
for(int re i=1;i<n;++i)ans+=(b[i]-1)*mn[i];
cout<<std::fixed<<std::setprecision(2)<<ans+DMST(n)<<"\n";
return 0;
}