顯然先選每一個點都取一遍而後再取滿次數最優,用最小樹形圖決定第一次取的順序。算法
朱劉算法的流程是(總複雜度O(nm)):spa
1.對除根外全部點,找到全部指向它的邊中權值最小的那一條,記其權值爲ind[]。code
2.找到全部不包含根的、由(1)中找到的那些邊構成的環,並將環縮點。若沒有這樣的環則結束。blog
3.將全部縮點後不是自環的邊的權值,減去邊的終點的ind。it
主要思路就是貪心+調整,具體看代碼實現。io
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 4 using namespace std; 5 6 const int N=61,M=21000; 7 const double inf=1e10; 8 int n=1,m,m1,n1,x,y,cnt,num[N],pos[N],pre[N],id[N],vis[N]; 9 double a[N],ans,v,ind[N]; 10 struct E{ int u,v; double w; }e[M]; 11 12 double Zhuliu(int rt,int n,int m){ 13 int tn,tm; double res=0; 14 while (1){ 15 rep(i,1,n) ind[i]=inf,pre[i]=id[i]=vis[i]=0; 16 tn=tm=ind[rt]=0; 17 rep(i,1,m) if (e[i].w<ind[e[i].v]) ind[e[i].v]=e[i].w,pre[e[i].v]=e[i].u; 18 rep(i,1,n){ 19 int x=i; res+=ind[i]; 20 while (x!=rt && vis[x]!=i && !id[x]) vis[x]=i,x=pre[x]; 21 if (x!=rt && !id[x]){ 22 id[x]=++tn; 23 for (int k=pre[x]; k!=x; k=pre[k]) id[k]=tn; 24 } 25 } 26 if (!tn) break; 27 rep(i,1,n) if (!id[i]) id[i]=++tn; 28 rep(i,1,m) if (id[e[i].u]!=id[e[i].v]) e[++tm]=(E){id[e[i].u],id[e[i].v],e[i].w-ind[e[i].v]}; 29 n=tn; m=tm; rt=id[rt]; 30 } 31 return res; 32 } 33 34 int main(){ 35 freopen("bzoj4349.in","r",stdin); 36 freopen("bzoj4349.out","w",stdout); 37 scanf("%d",&n1); 38 rep(i,1,n1){ 39 scanf("%lf%d",&v,&x); 40 if (x) pos[i]=++n,e[++m]=(E){1,n,v},a[n]=v,num[n]=x-1; 41 } 42 scanf("%d",&m1); 43 rep(i,1,m1){ 44 scanf("%d%d%lf",&x,&y,&v); 45 if (!pos[x] || !pos[y]) continue; 46 e[++m]=(E){pos[x],pos[y],v}; a[pos[y]]=min(a[pos[y]],v); 47 } 48 rep(i,2,n) ans+=a[i]*num[i]; 49 printf("%.2lf\n",Zhuliu(1,n,m)+ans); 50 return 0; 51 }