HDU 3452 Bonsai(最小割)

Bonsai

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 802    Accepted Submission(s): 406

Problem Description

After being assaulted in the parking lot by Mr. Miyagi following the "All Valley Karate Tournament", John Kreese has come to you for assistance. Help John in his quest for justice by chopping off all the leaves from Mr. Miyagi‘s bonsai
tree!

You are given an undirected tree (i.e., a connected graph with no cycles), where each edge (i.e., branch) has a nonnegative weight (i.e., thickness). One vertex of the tree has been designated the root of the tree.The remaining vertices of the tree each have
unique paths to the root; non-root vertices which are not the successors of any other vertex on a path to the root are known as leaves.Determine the minimum weight set of edges that must be removed so that none of the leaves in the original tree are connected
by some path to the root.

Input

The input file will contain multiple test cases. Each test case will begin with a line containing a pair of integers n (where 1 <= n <= 1000) and r (where r ∈ {1,……, n}) indicating the number of vertices in the tree and the index
of the root vertex, respectively. The next n-1 lines each contain three integers ui vi wi (where ui, vi ∈ {1,……, n} and 0 <= wi <= 1000) indicating that vertex ui is connected to
vertex vi by an undirected edge with weight wi. The input file will not contain duplicate edges. The end-of-file is denoted by a single line containing "0 0".

Output

For each input test case, print a single integer indicating the minimum total weight of edges that must be deleted in order to ensure that there exists no path from one of the original leaves to the root.

Sample Input

15 15
1 2 1
2 3 2
2 5 3
5 6 7
4 6 5
6 7 4
5 15 6
15 10 11
10 13 5
13 14 4
12 13 3
9 10 8
8 9 2
9 11 3
0 0

Sample Output

16

Source

2009 Stanford Local ACM Programming Contest

题意:给一棵n个节点的树,根节点为 r ,每条边都有一个花费。现在要求断开所有的叶子节点到根节点 r 的路径,问删除的边的花费最小是多少。

解题:最小割,源点VS=r ,新增一个汇点VT=n+1,叶子节点与汇点相连,边容为INF。其他的边按原输入建图就可以了。

/*
最大流:SAP算法,与ISAP的差别就是不用预处理
*/
#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
using namespace std;
#define captype int

const int MAXN = 1010;   //点的总数
const int MAXM = 400010;    //边的总数
const int INF = 1<<30;
struct EDG{
    int to,next;
    captype cap,flow;
} edg[MAXM];
int eid,head[MAXN];
int gap[MAXN];  //每种距离(或可认为是高度)点的个数
int dis[MAXN];  //每个点到终点eNode 的最短距离
int cur[MAXN];  //cur[u] 表示从u点出发可流经 cur[u] 号边
int pre[MAXN];

void init(){
    eid=0;
    memset(head,-1,sizeof(head));
}
//有向边 三个参数,无向边4个参数
void addEdg(int u,int v,captype c,captype rc=0){
    edg[eid].to=v; edg[eid].next=head[u];
    edg[eid].cap=c; edg[eid].flow=0; head[u]=eid++;

    edg[eid].to=u; edg[eid].next=head[v];
    edg[eid].cap=rc; edg[eid].flow=0; head[v]=eid++;
}
captype maxFlow_sap(int sNode,int eNode, int n){//n是包括源点和汇点的总点个数,这个一定要注意
    memset(gap,0,sizeof(gap));
    memset(dis,0,sizeof(dis));
    memcpy(cur,head,sizeof(head));
    pre[sNode] = -1;
    gap[0]=n;
    captype ans=0;  //最大流
    int u=sNode;
    while(dis[sNode]<n){   //判断从sNode点有没有流向下一个相邻的点
        if(u==eNode){   //找到一条可增流的路
            captype Min=INF ;
            int inser;
            for(int i=pre[u]; i!=-1; i=pre[edg[i^1].to])    //从这条可增流的路找到最多可增的流量Min
            if(Min>edg[i].cap-edg[i].flow){
                Min=edg[i].cap-edg[i].flow;
                inser=i;
            }
            for(int i=pre[u]; i!=-1; i=pre[edg[i^1].to]){
                edg[i].flow+=Min;
                edg[i^1].flow-=Min;  //可回流的边的流量
            }
            ans+=Min;
            u=edg[inser^1].to;
            continue;
        }
        bool flag = false;  //判断能否从u点出发可往相邻点流
        int v;
        for(int i=cur[u]; i!=-1; i=edg[i].next){
            v=edg[i].to;
            if(edg[i].cap-edg[i].flow>0 && dis[u]==dis[v]+1){
                flag=true;
                cur[u]=pre[v]=i;
                break;
            }
        }
        if(flag){
            u=v;
            continue;
        }
        //如果上面没有找到一个可流的相邻点,则改变出发点u的距离(也可认为是高度)为相邻可流点的最小距离+1
        int Mind= n;
        for(int i=head[u]; i!=-1; i=edg[i].next)
        if(edg[i].cap-edg[i].flow>0 && Mind>dis[edg[i].to]){
            Mind=dis[edg[i].to];
            cur[u]=i;
        }
        gap[dis[u]]--;
        if(gap[dis[u]]==0) return ans;  //当dis[u]这种距离的点没有了,也就不可能从源点出发找到一条增广流路径
                                        //因为汇点到当前点的距离只有一种,那么从源点到汇点必然经过当前点,然而当前点又没能找到可流向的点,那么必然断流
        dis[u]=Mind+1;//如果找到一个可流的相邻点,则距离为相邻点距离+1,如果找不到,则为n+1
        gap[dis[u]]++;
        if(u!=sNode) u=edg[pre[u]^1].to;  //退一条边
    }
    return ans;
}
int main()
{
    int n,VS ,VT ,u,v,w , d[MAXN];
    while(scanf("%d%d",&n,&VS)>0&&n+VS!=0){
        init();
        memset(d,0,sizeof(d));
        VT=n+1;
        for(int i=1; i<n; i++){
            scanf("%d%d%d",&u,&v,&w);
            d[u]++; d[v]++;
            addEdg(u,v,w);
            addEdg(v,u,w);
        }
        for(int i=1; i<=n; i++)
            if(i!=VS&&d[i]==1)
                addEdg(i,VT,INF);
        printf("%d\n",maxFlow_sap(VS,VT,VT));
    }
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-09 10:57:44

HDU 3452 Bonsai(最小割)的相关文章

HDU 3452 Bonsai(网络流之最小割)

题目地址:HDU 3452 最小割水题. 源点为根节点.再另设一汇点,汇点与叶子连边. 对叶子结点的推断是看度数是否为1. 代码例如以下: #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdlib.h> #include <math.h> #include <ctype.h> #include &l

HDU 3452 Bonsai

可以树形DP,也可以用网络流(最大流=最小割) 用树形DP的话,这题就是 HDU 3586 简化版,HDU 3586还需要二分查找. #include<cstdio> #include<cstring> #include<cmath> #include<ctime> #include<map> #include<vector> #include<string> #include<algorithm> #incl

HDU 4859 海岸线 最小割

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4859 题解: 这题考察的是最小割. 我们可以这样想:海岸线的长短变化都是E引起的,我们通过把’E'变成'.'或'D'来使海岸线最大化. 我们要算海岸线就是算格子‘.'和格子'D'(在原有地图周围四面都要加’D‘)相邻的面数,要使它最大,就是要使'.'与’.':'D'与'D'相邻的面数最小,而面数最小可以用最小割来做. 现在我们先把格子上的点黑白染色,(i+j)%2==1的为A类,为0的为B类, 在

HDU 3061 Battle(最小割----最大权闭合图)

题目地址:HDU 3061 多校中遇到的最小割的最大权闭合模型花了一上午时间终于看懂啦. 最大权闭合图就是将一些互相有依赖关系的点转换成图,闭合图指的是在图中的每一个点的后继点都是在图内的. 还要明白简单割的概念,就是指所有的割边都与源点或汇点相连.然后让源点与正权点相连,汇点与负权点相连,权值均为其绝对值,有依赖关系的点连一条有向边,如果a必须在b的基础上,那么就连一条a->b的有向边,权值为INF.最后用所有正权值得和减去最小割的值就是答案. 具体证明可看胡伯涛大牛的国家队集训论文<最小割

hdu 3987 求最小割条数最小

题意:    一个人要从起点  0  到达 n-1   n个点  m条路  ,我们求最少破坏路的条数使无法 从起点到达终点.题意很明显  ,求最小割条数最少,由于最小割流量虽然固定,但是其条数却不固定,可以破坏3条路,也可以破坏4条路,他们总流量相同才会出现这种情况. 题解:由于上述的情况,他们总流量相同但是条数不同,现在我们需要改变边的容量使得条数少边才是最小割,条数多的将不会是最小割. 官方题解有两种 ,我选择的是在残余网络中进行扩充流的操作,使的两个最小割不同,残余网络中,我进行所有边流量

hdu 3657 Game 最小割

首先经典的奇偶建立二分图(X,Y),对于相邻两点连边2*(X&Y),源->X连边,Y->汇连边,权值w为点权,求最小割. 考虑一条路径 源->X->Y->汇 若割边选取的是源->X,则表示选Y点不选X点, 答案为w(X+Y)-w(X) 若割边选取的是Y->,则表示选X点不选Y点, 答案为w(X+Y)-w(Y) 若割边选取的是X->Y,则表示选Y点且选X点, 答案为w(X+Y)-w( 2*(X&Y) ) 即总点权-最小割 #include<

HDU - 4289 Control (最小割 MCMF)

题目大意:有一个间谍要将一些机密文件送到目的地 现在给出间谍的初始位置和要去的目的地,要求你在间谍的必经路上将其拦获且费用最小 解题思路:最小割最大流的应用,具体可以看网络流–最小割最大流 建图的话 超级源点–起始城市,容量为INF 城市拆成两点(u, v),容量为监视该城市的代价 能连通的城市连接,容量为INF 目的地和超级汇点相连,容量为INF #include <cstdio> #include <cstring> #include <algorithm> #in

HDU 3046【最小割】

题目大意:在一个n*m的矩阵上,1代表羊,2代表狼,0代表平地,我们有长度为1的一个栅栏(不是放在格子上的,是放在格子和格子之间的空隙上的),问使用最少的栅栏,能够使得狼吃不到羊. 又学到了一招,以前一直以为建图是要先设好S点T点,在把其他的点和他们两一一相连.今天学到了原来可以在整个map上根据条件建好图,再把其中的某些目标点和源汇点相连的. 思路如下: 1.建立最小割模型: ①建立源点S,将源点S连入各个有狼的节点上,权值设定为INF,表示狼可以从任意方向出发. ②建立汇点T,将各个羊节点连

HDU 4289 Control 最小割

Control 题意:有一个犯罪集团要贩卖大规模杀伤武器,从s城运输到t城,现在你是一个特殊部门的长官,可以在城市中布置眼线,但是布施眼线需要花钱,现在问至少要花费多少能使得你及时阻止他们的运输. 题解:裸的最小割模型,最小割就是最大流,我们把点拆成2个点,然后将原点与拆点建边,流量为在城市建立眼线的费用,然后拆点为出点,原点为入点,将可以到达的城市之间建流量为无穷的边. 最后求出s 到 t的拆点的最大流 那么就是这个题目的答案了. 代码: 1 #include<bits/stdc++.h>