[BZOJ4349]最小樹形圖

顯然先選每一個點都取一遍而後再取滿次數最優,用最小樹形圖決定第一次取的順序。算法

朱劉算法的流程是(總複雜度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 }
相關文章
相關標籤/搜索