POJ3585
题解
- 选择一个点,使它到所有端点的流量和最大。
- 一棵树,我们可求每个结点到子树的端点的最大流量和。DFS一遍,自低先上。设g[u]表示到u结点到子树端点的最大流量和,那么g[u] += min(g[v],e.cap)。v为root的子节点,e.cap表示这一条边的容量。如果下一个结点使叶子结点,那么直接加上e.cap,即g[u] += e.cap。
- 然后再DFS一遍,求结点到所有端点的流量和,用f[u]表示。u的父节点为fa,他们中间的表为e,则f[u]肯定包含g[u],往下流的一定在。还有一部分往父亲节点,最大可流e.cap。其值为min(e.cap,f[fa] - min (e.cap,g[u]))。因为是自顶向下,所以fa往所有端点的流量已经求好了。
- 注意第二遍dfs时,初始化f[1] = g[1],根节点只能玩往下流。
- 如果根节点只有一个儿子,那么要特判。f[u] = g[u] + e.cap。
代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
using namespace std;
int const N = 200000 + 10;
int n,g[N],f[N];
struct Node
{
int to,cap;
Node(){}
Node(int to,int cap):to(to),cap(cap){}
};
vector<Node>G[N];
void dfs1(int u,int fa){ //自低向上
for(int i=0;i<G[u].size();i++){
Node e = G[u][i];
if(e.to == fa) continue;
dfs1(e.to,u);
if(G[e.to].size() == 1) g[u] += e.cap;
else g[u] += min(e.cap,g[e.to]);
}
}
void dfs2(int u,int fa){ //自顶向下
for(int i=0;i<G[u].size();i++){
Node e = G[u][i];
if(e.to == fa) continue; //叶结点已经直接跳过了
if(G[u].size() == 1) f[e.to] = g[e.to] + e.cap;
else f[e.to] = g[e.to] + min(e.cap,f[u] - min(e.cap,g[e.to]));
dfs2(e.to,u);
}
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
memset(g,0,sizeof(g));
memset(f,0,sizeof(f));
for(int i=1;i<=n;i++) G[i].clear();
for(int i=1;i<n;i++){
int u,v,c;
scanf("%d%d%d",&u,&v,&c);
G[u].push_back(Node(v,c));
G[v].push_back(Node(u,c));
}
dfs1(1,0);
f[1] = g[1];
dfs2(1,0);
int ans = 0;
for(int i=1;i<=n;i++)
ans = max(ans,f[i]);
cout<<ans<<endl;
}
return 0;
}
CF219D
题解
- 有向树,找一个结点,反转的最少的边,可以到所有的结点。
- 正向边用1表示,反向边用0表示。那么所求的点满足,经过所有的边的权值和最大。
- 同上,两次DFS。第一次求点到字数所有结点的权值和g。再反转一次DFS,求到父亲的权值和f。最后就是g + f。
代码
#include <bits/stdc++.h>
using namespace std;
int const N = 200000 + 10;
int n,g[N],f[N];
struct Node
{
int to,val;
Node(){}
Node(int to,int val):to(to),val(val){}
};
struct Node1
{
int id,v;
bool operator < (const Node1& e)const{
return v > e.v || v == e.v && id < e.id;
}
}ans[N];
vector<Node>G[N];
void dfs(int u,int fa){
for(int i=0;i<G[u].size();i++){
Node e = G[u][i];
if(e.to == fa) continue;
dfs(e.to,u);
g[u] += e.val;
g[u] += g[e.to];
}
}
void dfs2(int u,int fa){
for(int i=0;i<G[u].size();i++){
Node e = G[u][i];
if(e.to == fa) continue;
f[e.to] = g[e.to] + (f[u] - g[e.to] - e.val) + (e.val ? 0 : 1);
dfs2(e.to,u);
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n-1;i++){
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(Node(v,1));
G[v].push_back(Node(u,0));
}
dfs(1,-1);
f[1] = g[1];
dfs2(1,-1);
for(int i=1;i<=n;i++){
ans[i].id = i;
ans[i].v = f[i];
}
sort(ans+1,ans+1+n);
int sum = 1;
for(int i=2;i<=n;i++)
if(ans[i].v == ans[1].v) sum++;
printf("%d\n",n - 1 - ans[1].v); //总共有n-1条边,不需要修改的为ans[sum].v
for(int i=1;i<=sum;i++)
printf("%d%c",ans[i].id,i == sum ? '\n' : ' ');
return 0;
}