洛谷 P3931 SAC E#1 - 一道难题 Tree

洛谷 P3931 SAC E#1 - 一道难题 Tree

洛谷传送门

题目背景

冴月麟和魏潇承是好朋友。

题目描述

冴月麟为了守护幻想乡,而制造了幻想乡的倒影,将真实的幻想乡封印了。任何人都无法进入真实的幻想乡了,但是她给前来救她的魏潇承留了一个线索。

她设置了一棵树(有根)。树的每一条边上具有割掉该边的代价。

魏潇承需要计算出割开这棵树的最小代价,这就是冴月麟和魏潇承约定的小秘密。

帮帮魏潇承吧。

注:所谓割开一棵有根树,就是删除若干条边,使得任何任何叶子节点和根节点不连通。

输入格式

输入第一行两个整数n,S表示树的节点个数和根。

接下来n-1行每行三个整数a、b、c,表示a、b之间有一条代价为c的边。

输出格式

输出包含一行,一个整数,表示所求最小代价。


题解:

题意就很像最小割裸题。但是最小割只要求汇点与源点不联通,这道题要求所有叶子节点都不连通。很容易啊,建超级汇点就好了。

然后根据最大流最小割定理,直接在上面跑Dinic最大流。

代码:(不知道为什么,这份代码会MLE一半的点,如有大佬请指正)

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=1e5+5;
const int INF=1e9;
int n,s,t,ans;
int tot=1,head[maxn],nxt[maxn<<1],to[maxn<<1],val[maxn<<1];
int lv[maxn],cur[maxn];
bool v[maxn];
queue<int> q;
void add(int x,int y,int z)
{
    to[++tot]=y;
    nxt[tot]=head[x];
    val[tot]=z;
    head[x]=tot;
}
void dfs_pre(int x,int f)
{
    bool flag=0;
    for(int i=head[x];i;i=nxt[i])
    {
        int y=to[i];
        if(y==f)
            continue;
        flag=1;
        dfs_pre(y,x);
        val[i^1]=0;
    }
    if(!flag)
    {
        add(x,t,INF);
        add(t,x,0);
    }
}
bool bfs()
{
    memset(lv,0,sizeof(lv));
    lv[s]=1;
    q.push(s);
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        for(int i=head[x];i;i=nxt[i])
        {
            int y=to[i];
            if(!val[i]||lv[y])
                continue;
            lv[y]=lv[x]+1;
            q.push(y);
        }
    }
    return lv[t];
}
int dfs(int x,int flow)
{
    if(!flow||x==t)    
        return flow;
    int re=0;
    for(int i=cur[x];i;i=nxt[i])
    {
        cur[x]=i;
        int y=to[i];
        if(val[i]>0 && lv[y]==lv[x]+1)
        {
            int tmp=dfs(y,min(val[i],flow));
            if(!tmp)
                continue;
            flow-=tmp;
            re+=tmp;
            val[i]-=tmp;
            val[i^1]+=tmp;
        }
    }
    return re;
}
int main()
{
    scanf("%d%d",&n,&s);
    t=n+1;
    for(int i=1;i<n;i++)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        add(a,b,c);
        add(b,a,c);
    }
    dfs_pre(s,-1);
    while(bfs())
    {
        memcpy(cur,head,sizeof(head));
        ans+=dfs(s,INF);
    }
    printf("%d\n",ans);
    return 0;
}
posted @ 2020-11-29 14:50  Seaway-Fu  阅读(71)  评论(0编辑  收藏  举报