BZOJ 3876 支線劇情 有源匯有上下界最小費用可行流

題意:

  給定一張拓撲圖,每條邊有邊權,每次只能從第一個點出發沿着拓撲圖走一條路徑,求遍歷全部邊所須要的最小邊權和node

分析:

  這道題乍一看,可能會想到什麼最小鏈覆蓋之類的,可是仔細一想,會發現不行,一是由於每條邊都會有貢獻,而不是每條鏈,二是由於邊有特定的邊權,因此這道題只能用建圖複雜一些的網絡流來解決。c++

  其實也挺簡單的。都不用建超級源點,直接從1號點當源點就行,每條邊費用爲邊權,容量下界爲1,上界無窮大。網絡

  而後建圖跑最小費用可行流就能夠了。ide

代碼:spa

 1 #include<bits/stdc++.h>
 2 using namespace std;int S,T,tot=0;
 3 const int N=505,M=500005,inf=0x3f3f3f3f;
 4 struct node{int y,f,c,nxt;}e[M];int c=1,t[N];
 5 int h[N],q[M],d[N],n,m,s,pre[N];bool vis[N];
 6 void add(int x,int y,int z,int w){
 7     e[++c]=(node){y,z,w,h[x]};h[x]=c;
 8     e[++c]=(node){x,0,-w,h[y]};h[y]=c;
 9 } bool spfa(){
10     for(int i=0;i<=T;i++) d[i]=inf;
11     int l=1,r=0;q[++r]=S;vis[S]=1;d[S]=0;
12     while(l<=r){ 
13         int x=q[l++];vis[x]=0;
14         for(int i=h[x],y;i;i=e[i].nxt)
15         if(d[y=e[i].y]>d[x]+e[i].c&&e[i].f){
16             d[y]=d[x]+e[i].c;pre[y]=i;
17             if(!vis[y]) q[++r]=y,vis[y]=1;}
18     } return (d[T]!=inf);
19 } void aug(){ int x=inf;
20     for(int i=pre[T];i;i=pre[e[i^1].y]) 
21     x=min(x,e[i].f);
22     for(int i=pre[T];i;i=pre[e[i^1].y])
23     tot+=x*e[i].c,e[i].f-=x,e[i^1].f+=x;
24 } int main(){
25     scanf("%d",&n);S=1,T=n+1;
26     for(int i=1,k,y,v;i<=n;i++){
27         scanf("%d",&k);while(k--)
28         scanf("%d%d",&y,&v),
29         add(i,y,inf,v),t[y]++,t[i]--,tot+=v;
30     } for(int i=1;i<=n;i++)
31     if(t[i]>0) add(S,i,t[i],0);
32     else if(t[i]<0) add(i,T,-t[i],0);
33     while(spfa()) aug();
34     printf("%d\n",tot);return 0;
35 }
有源匯有上下界最小費用可行流
相關文章
相關標籤/搜索