1. 程式人生 > 實用技巧 >洛谷 P3931 SAC E#1 - 一道難題 Tree

洛谷 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;
}