51nod 1325 兩棵樹的問題(最大權閉合子圖)
阿新 • • 發佈:2019-02-26
getc dinic 最小 n+1 while stream The ring 集合
首先如果點權全都為正,就可以直接選所有的點。
活在夢裏。。
考慮枚舉一個點\(i\),作為我們選擇的集合中的一個點。
然後我們把另一個點\(j\)選入集合的時候必須把兩棵樹中\(i\)和\(j\)路徑上的點全都選入集合。
似乎想到了什麽。
閉合子圖。
不就是一個最大權閉合子圖嗎。
然後我們按最大權閉合子圖的模型建圖。
所有正權的點跟\(S\)連容量為權值的邊。
所有負權的點跟\(T\)連容量為權值絕對值的邊。
我們把枚舉的i作為兩個樹上的根。
然後每一個點跟兩顆樹上的\(father\)連容量為\(INF\)的邊。
然後正權總和-最小割就是答案。
#include<iostream> #include<cmath> #include<cstring> #include<cstdio> #include<algorithm> #include<queue> using namespace std; const int INF=1e9; const int N=110; int cnt,head[N]; struct edge{ int to,nxt,flow; }e[N*6]; void add_edge(int u,int v,int flow){ cnt++; e[cnt].nxt=head[u]; e[cnt].to=v; head[u]=cnt; e[cnt].flow=flow; } int cn,hed[N]; struct ed{ int to,nxt; }ee[N*2]; void add(int u,int v){ cn++; ee[cn].nxt=hed[u]; ee[cn].to=v; hed[u]=cn; } int f1[N]; void dfs1(int u,int f){ f1[u]=f; for(int i=hed[u];i;i=ee[i].nxt){ int v=ee[i].to; if(v==f)continue; dfs1(v,u); } } int f2[N]; void dfs2(int u,int f){ f2[u]=f; for(int i=hed[u];i;i=ee[i].nxt){ int v=ee[i].to; if(v==f)continue; dfs2(v,u); } } int dis[N],S,T; bool bfs(){ memset(dis,-1,sizeof(dis)); dis[S]=0; queue<int> q; q.push(S); while(!q.empty()){ int u=q.front(); q.pop(); for(int i=head[u];i;i=e[i].nxt){ int v=e[i].to; if(dis[v]==-1&&e[i].flow){ dis[v]=dis[u]+1; q.push(v); } } } if(dis[T]==-1)return false; return true; } int dfs(int u,int f){ if(u==T||f==0)return f; int used=0; for(int i=head[u];i;i=e[i].nxt){ int v=e[i].to; if(dis[v]==dis[u]+1&&e[i].flow){ int w=dfs(v,min(f-used,e[i].flow)); if(w){ e[i].flow-=w; e[i^1].flow+=w; used+=w; if(used==f)return f; } } } if(used==0)dis[u]=-1; return used; } int tmp; void Dinic(){ while(bfs())tmp+=dfs(S,INF); } int read(){ int sum=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();} return sum*f;; } int n,a[N],tot,ans; int main(){ n=read(); for(int i=1;i<=n;i++)a[i]=read(); for(int i=1;i<n;i++){ int u=read()+1,v=read()+1; add(u,v);add(v,u); } for(int i=1;i<n;i++){ int u=read()+n+1,v=read()+n+1; add(u,v);add(v,u); } for(int i=1;i<=n;i++){ dfs1(i,0);dfs2(i+n,0); cnt=1;memset(head,0,sizeof(head));tot=0; S=0,T=n+1; for(int j=1;j<=n;j++) if(a[j]<0)add_edge(j,T,-a[j]),add_edge(T,j,0); else add_edge(S,j,a[j]),add_edge(j,S,0),tot+=a[j]; for(int j=1;j<=n;j++){ if(j==i)continue; add_edge(j,f1[j],INF);add_edge(f1[j],j,0); add_edge(j,f2[j+n]-n,INF);add_edge(f2[j+n]-n,j,0); } tmp=0; Dinic(); ans=max(ans,tot-tmp); } printf("%d",ans); return 0; }
51nod 1325 兩棵樹的問題(最大權閉合子圖)