HDU3452_Bonsai

题目的意思是给你一个棵树,每天边上有一个权值,现在要想根节点和每个叶子节点完全隔离开来,删除一些边,求最少需要删除的边权值综合是多少?

直接建模,以根节点为汇点,每个叶子节点连接虚拟源点流量无穷,树上的节点按原样建模就可以了。

最后跑一遍最大流等于最小割,完美解决。

召唤代码君:

#include <iostream>
#include <cstdio>
#include <cstring>
#define maxn 20010
#define inf 1999999999
using namespace std;

int first[maxn],to[maxn],c[maxn],next[maxn],N;
int d[maxn],a[maxn],can[maxn],tag[maxn],TAG=520;
int s,t,n,m,ans;
int Q[maxn],bot,top;

void _init()
{
    N=-1,ans=0,s=0,t=m;
    for (int i=0; i<=n; i++) first[i]=-1,a[i]=0;
}

void edge(int U,int V,int W)
{
    N++;
    to[N]=V,c[N]=W,next[N]=first[U],first[U]=N;
}

void _input()
{
    int U,V,W;
    for (int i=1; i<n; i++)
    {
        scanf("%d%d%d",&U,&V,&W);
        edge(U,V,W),edge(V,U,W);
        a[U]++,a[V]++;
    }
    for (int i=1; i<=n; i++)
        if (a[i]==1 && i!=t) edge(s,i,inf),edge(i,s,0);
}

bool bfs()
{
    TAG++;
    Q[bot=top=1]=t,d[t]=1,tag[t]=TAG;
    while (bot<=top)
    {
        int cur=Q[bot++];
        for (int i=first[cur]; i!=-1; i=next[i])
        {
            if (c[i^1]<=0 || tag[to[i]]==TAG) continue;
            d[to[i]]=d[cur]+1,Q[++top]=to[i],tag[to[i]]=TAG;
            //if (to[i]==s) return true;
        }
    }
    return tag[s]==TAG;
    return false;
}

int dfs(int cur,int num)
{
    if (cur==t) return num;
    int tmp=num,k;
    for (int i=first[cur]; i!=-1; i=next[i])
    {
        if (c[i]<=0 || tag[to[i]]!=TAG || d[to[i]]!=d[cur]-1 || can[to[i]]==TAG) continue;
        k=dfs(to[i],min(num,c[i]));
        if (k) c[i]-=k,c[i^1]+=k,num-=k;
        if (num==0) break;
    }
    if (num) can[cur]=TAG;
    return tmp-num;
}

int main()
{
    while (scanf("%d%d",&n,&m)&&(n|m))
    {
        _init();
        _input();
        while (bfs()) ans+=dfs(s,inf);
        printf("%d\n",ans);
    }
    return 0;
}

  

HDU3452_Bonsai

时间: 2024-10-26 00:36:29

HDU3452_Bonsai的相关文章