总之就是 | SP300 & UVA1660 Cable TV Network

前言

实际上这两道是基本上一样的((

但是为了洛谷的题解同步我就都贴过来了。

SP300

题意简述

题目给出 T 个图,每个图有 n 个结点,m 条边,求最少去掉几个结点可以使给出的图不连通。

前置芝士

最小割

解决“最少去掉几个结点可以使网络的源点和汇点不连通”的问题时,我们常用到这样一个概念:最小割

给定一个网络 \(G=(V,E)\),设其源点为 S,汇点为 T。若一个边的集合 \(E' \subseteq E\) 被删掉后 S 和 T 不再联通,则称这个边集 \(E'\) 是该网络的

最小割就定义为边集内边的容量之和最小的割。

最大流最小割定理

即:任意一个网络的最大流量等于最小割中边的容量之和。

简单来说就是最大流量 = 最小割容量

思路简述

注意到,题目的所求和我们常用最小割解决的那个问题很像,于是我们考虑将当前图上的问题转化到网络上求解。

联想一下两者的关系:网络本质上也是一张图,只不过多了源点和汇点。

于是我们就有了将图转化为网络求解的思路:枚举源点和汇点!

这个想法很暴力,不过同样也带来了更少的思维量。

因此我们可以直接枚举源点和汇点,再用 Dinic 求网络最大流(最小割)来切掉这道题。

Code

看似代码很长,实际上都是非常基础的东西组合起来的,所以建议大家还是先自己写。

//头文件略
#define Heriko return
#define Deltana 0
#define Romano 1
#define S signed
#define LL long long
#define R register
#define I inline
#define CI const int
#define mst(a, b) memset(a, b, sizeof(a))
#define ON std::ios::sync_with_stdio(false)
using namespace std;

template<typename J>
I void fr(J &x) {...//快读略}

template<typename J>
I void fw(J x,bool k) {...//快输略}

template<typename J>
I J Hmin(J x,J y) {Heriko x<y?x:y;}

template<typename J>
I void Clear(queue<J> &x) {while(x.size()) x.pop();}

CI MXX=40005,NXX=105,ABXX=2505,inf=998244353;

struct node
{
    LL nex,to,val;
}

r[MXX];

LL n,m,cnt,head[NXX],dis[NXX],now[NXX],maxflow,s,t;

queue<LL> q;

I void Ass_we_can(LL x,LL y,LL z)
{
    r[++cnt].to=y,r[cnt].nex=head[x],r[cnt].val=z;head[x]=cnt;
    r[++cnt].to=x,r[cnt].nex=head[y],r[cnt].val=0;head[y]=cnt;
}

I bool BFS()
{
    mst(dis,0);
    Clear(q);
    q.push(s);dis[s]=1;now[s]=head[s];
    while(q.size())
    {
        LL x=q.front();q.pop();
        for(R LL i=head[x];i;i=r[i].nex)
        {
            LL y=r[i].to;
            if(!dis[y] and r[i].val)
            {
                q.push(y);
                dis[y]=dis[x]+1;
                now[y]=head[y];
                if(y==t) Heriko Romano;
            }
        }
    }
    Heriko Deltana;
}

LL Dinic(LL x,LL flow)
{
    if(x==t) Heriko flow;
    LL i,y,k,rst=flow;
    for(i=now[x];i and rst;i=r[i].nex)
    {
        y=r[i].to;
        if(r[i].val and dis[y]==dis[x]+1)
        {
            k=Dinic(y,Hmin(r[i].val,rst));
            if(!k) dis[y]=0;
            r[i].val-=k;
            r[i^1].val+=k;
            rst-=k;
        }
    }
    now[x]=i;
    Heriko flow-rst;
}

LL a[ABXX],b[ABXX],flow,ans,T;

S main()
{
    // freopen("RNMTQ.in","r",stdin);
    fr(T);
    while(T--)
    {
        fr(n),fr(m);
        for(R LL i=0;i<m;++i)
        {
            char s[55];LL j;
            scanf("%s",s);
            a[i]=b[i]=0;
            for(j=1;s[j]!=',';++j) a[i]=a[i]*10+s[j]-'0';
            for(j++;s[j]!=')';++j) b[i]=b[i]*10+s[j]-'0';
        }
        ans=inf;
        for(s=0;s<n;++s)
            for(t=0;t<n;++t)
                if(s!=t)
                {
                    mst(head,0);cnt=1;maxflow=0;flow=0;
                    for(R LL i=0;i<n;++i)
                    {
                        if(i==s or i==t) Ass_we_can(i,i+n,inf);
                        else Ass_we_can(i,i+n,1);
                    }
                    for(R LL i=0;i<m;++i) Ass_we_can(a[i]+n,b[i],inf),Ass_we_can(b[i]+n,a[i],inf);
                    while(BFS())
                        while((flow=Dinic(s,inf))) maxflow+=flow;
                    ans=Hmin(maxflow,ans);
                }
        if(n<=1 or ans==inf) ans=n;
        fw(ans,1);
    }
    Heriko Deltana;
}

希望能给大家带来收获。

UVA1660 Cable TV Network

SP300和这题基本一样罢。

前置芝士

最小割

给定一个网络 \(G=(V,E)\),设其源点为 S,汇点为 T。若一个边的集合 \(E' \subseteq E\) 被删掉后 S 和 T 不再联通,则称这个边集 \(E'\) 是该网络的

最小割就定义为边集内边的容量之和最小的割。

最大流最小割定理

即:任意一个网络的最大流量等于最小割中边的容量之和。

简单来说就是最大流量 = 最小割容量

Dinic 求最小割

由上面的定理可得求最小割的容量实际上就是求网络最大流量,所以我们可以直接用 Dinic 去求网络最大流:


I bool BFS()
{
    mst(dis,0);
    Clear(q);
    q.push(s);dis[s]=1;now[s]=head[s];
    while(q.size())
    {
        LL x=q.front();q.pop();
        for(R LL i=head[x];i;i=r[i].nex)
        {
            LL y=r[i].to;
            if(!dis[y] and r[i].val)
            {
                q.push(y);
                dis[y]=dis[x]+1;
                now[y]=head[y];
                if(y==t) Heriko Romano;
            }
        }
    }
    Heriko Deltana;
}

LL Dinic(LL x,LL flow)
{
    if(x==t) Heriko flow;
    LL i,y,k,rst=flow;
    for(i=now[x];i and rst;i=r[i].nex)
    {
        y=r[i].to;
        if(r[i].val and dis[y]==dis[x]+1)
        {
            k=Dinic(y,Hmin(r[i].val,rst));
            if(!k) dis[y]=0;
            r[i].val-=k;
            r[i^1].val+=k;
            rst-=k;
        }
    }
    now[x]=i;
    Heriko flow-rst;
}

题意简述

直接看 UVA 的 PDF 有点慢,于是我在这里挂一个 Vjudge 的链接

给你有 n 个结点,m 条边的图,求最少去掉几个结点可以使给出的图不连通。

题目有多组数据,也就是说有多个图。

思路简述

解决“最少去掉几个结点可以使网络的源点和汇点不连通”的问题时,我们常用到最小割,于是我们考虑转换求解。

联想一下两者的关系:网络本质上也是一张图,只不过就多了源点和汇点。

因此我们可以直接枚举源点和汇点,再用 Dinic 求网络最大流(最小割)来切掉这道题。

这个想法很暴力,不过同样也带来了更少的思维量,而更少的思维量意味着更我们写起代码来更加轻松愉悦~

Code

在放代码之前,发现这题在洛谷居然没有样例,于是我就把样例放在这里方便大家罢。

输入:

0 0
1 0
3 3 (0,1) (0,2) (1,2)
2 0
5 7 (0,1) (0,2) (1,3) (1,2) (1,4) (2,3) (3,4)

输出:

0
1
3
0
2
//头文件略
#define Heriko return
#define Deltana 0
#define Romano 1
#define S signed
#define LL long long
#define R register
#define I inline
#define CI const int
#define mst(a, b) memset(a, b, sizeof(a))
#define ON std::ios::sync_with_stdio(false)
using namespace std;

template<typename J>
I void fr(J &x) {...//快读略}

template<typename J>
I void fw(J x,bool k) {...//快输略}

template<typename J>
I J Hmin(J x,J y) {Heriko x<y?x:y;}

template<typename J>
I void Clear(queue<J> &x) {while(x.size()) x.pop();}

CI MXX=40005,NXX=105,ABXX=2505,inf=998244353;

struct node
{
    LL nex,to,val;
}

r[MXX];

LL n,m,cnt,head[NXX],dis[NXX],now[NXX],maxflow,s,t;

queue<LL> q;

I void Ass_we_can(LL x,LL y,LL z)
{
    r[++cnt].to=y,r[cnt].nex=head[x],r[cnt].val=z;head[x]=cnt;
    r[++cnt].to=x,r[cnt].nex=head[y],r[cnt].val=0;head[y]=cnt;
}

I bool BFS() {...//BFS略}

LL Dinic(LL x,LL flow) {...//Dinic略}

LL a[ABXX],b[ABXX],flow,ans,T;

S main()
{
    // freopen("RNMTQ.in","r",stdin);
    while(scanf("%lld%lld",&n,&m)==2)//要注意本题的输入格式
    {
        for(R LL i=0;i<m;++i)
        {
            char s[55];LL j;
            scanf("%s",s);
            a[i]=b[i]=0;
            for(j=1;s[j]!=',';++j) a[i]=a[i]*10+s[j]-'0';
            for(j++;s[j]!=')';++j) b[i]=b[i]*10+s[j]-'0';
        }
        ans=inf;
        for(s=0;s<n;++s)
            for(t=0;t<n;++t)
                if(s!=t)
                {
                    mst(head,0);cnt=1;maxflow=0;flow=0;
                    for(R LL i=0;i<n;++i)
                    {
                        if(i==s or i==t) Ass_we_can(i,i+n,inf);
                        else Ass_we_can(i,i+n,1);
                    }
                    for(R LL i=0;i<m;++i) Ass_we_can(a[i]+n,b[i],inf),Ass_we_can(b[i]+n,a[i],inf);
                    while(BFS())
                        while((flow=Dinic(s,inf))) maxflow+=flow;
                    ans=Hmin(maxflow,ans);
                }
        if(n<=1 or ans==inf) ans=n;
        fw(ans,1);
    }
    Heriko Deltana;
}

希望能给大家带来收获~

posted @ 2021-06-30 21:15  HerikoDeltana  阅读(608)  评论(0编辑  收藏  举报