51Nod 1299 監獄逃離

這實際上是一道樹形DP的神仙題。git

而後開始推推推,1 hour later樣例都過不了網絡

而後仔細一看題目,貌似像一個最小割模型,而後5min想了想建圖:spa

  1. 首先拆點,將每一個點拆成進和出兩個,而後連邊,邊權即爲\(1\)(表示割掉這條邊的代價)
  2. 而後設超級源\(S\),讓\(S\)向全部犯人的出點(由於犯人的點沒法割去)連邊,邊權爲\(\infty\),而後對於全部的出口(葉子節點),都向\(T\)連邊,邊權爲\(\infty\)
  3. 最後根據題目給出的關係建邊,而後由於這些邊不能夠被割掉,所以邊權爲\(\infty\)

而後聽說Dinic的最劣複雜度是\(O(n^2m)\)的,因此直接沒有畏懼地交了.net

而後A了?!第一次看到51Nod的題數據這麼水(而後莫名複習了一波網絡流code

固然正解是樹形DP,固然能夠看陳瀟然dalao的博客blog

DinicCODEget

#include<cstdio>
#include<cstring>
#include<cctype>
using namespace std;
const int N=100005,INF=1e9;
struct edge
{
    int to,next,c;
}e[N<<4];
int head[N<<1],n,cnt=-1,m,x,y,dep[N<<1],q[N<<1],s,t,l[N<<1];
inline char tc(void)
{
    static char fl[100000],*A=fl,*B=fl;
    return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
    x=0; char ch; while (!isdigit(ch=tc()));
    while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
}
inline void double_add(int x,int y,int z)
{
    e[++cnt].to=y; e[cnt].next=head[x]; e[cnt].c=z; head[x]=cnt; ++l[x];
    e[++cnt].to=x; e[cnt].next=head[y]; e[cnt].c=0; head[y]=cnt; ++l[y];
}
inline int min(int a,int b)
{
    return a<b?a:b;
}
inline bool BFS(void)
{
    memset(dep,0,sizeof(dep));
    int H=0,T=1; dep[s]=1; q[1]=s;
    while (H<T)
    {
        int now=q[++H];
        for (register int i=head[now];~i;i=e[i].next)
        if (e[i].c&&!dep[e[i].to])
        {
            dep[e[i].to]=dep[now]+1;
            q[++T]=e[i].to;
        }
    }
    return dep[t];
}
inline int DFS(int now,int dist)
{
    if (now==t) return dist; int res=0;
    for (register int i=head[now];~i&&dist;i=e[i].next)
    if (e[i].c&&dep[e[i].to]==dep[now]+1)
    {
        int dis=DFS(e[i].to,min(dist,e[i].c));
        dist-=dis; res+=dis;
        e[i].c-=dis; e[i^1].c+=dis;
    }
    if (!res) dep[now]=0;
    return res;
}
inline int Dinic(void)
{
    int tot=0;
    while (BFS()) tot+=DFS(s,INF);
    return tot>=INF?-1:tot;
}
int main()
{
    //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    register int i; read(n); ++n; read(m); s=0; t=(n<<1)+1;
    memset(head,-1,sizeof(head));
    for (i=1;i<n;++i)
    read(x),read(y),++x,++y,double_add(x+n,y,INF),double_add(y+n,x,INF);
    for (i=1;i<=m;++i)
    read(x),++x,double_add(s,x+n,INF);
    for (i=1;i<=n;++i)
    {
        if (l[i]==1) double_add(i+n,t,INF);
        double_add(i,i+n,1);
    }
    return printf("%d",Dinic()),0;
}
相關文章
相關標籤/搜索