码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ 2561 最小生成树 最小割

时间:2015-07-24 20:56:53      阅读:103      评论:0      收藏:0      [点我收藏+]

标签:

题意:链接

方法:最小割

解析:

首先要明确一个事情,

就是一条边为一个正权无向图中被选为最小生成树上的边的充要条件是什么?

条件为:在该正权无向图中,不存在一个环,该边在此环上,并且该边为该环中权值最大的边。

这是为什么呢?

打个比方,现在我们在一个无向图中找到了一棵树和一个环,假设该树就是抛去该环以外的最小生成树,那么,在整个图中,最小生成树是什么样的呢?

从该环中选取与该树相连的一点并且选取该环中最小的该环节点数-1条边,即这个环的最大边不会被选入最小生成树中。

QED

可能言语欠佳,但思路如此,还请神犇多有包涵。


反正我是差不多这么YY的,但总有种不充要的感觉,所以各路神犇看到这个题解后如果会证明的话请留言我,万分感谢。


有了如上的先决条件,我们可以搞这道题了,即比题中额外给的边小的边绝对不能形成环。那么我们把所有比该边小的边都加一条权值为1的边,之后跑最小割(最大流),求出了最少删去多少边能使得无环出现。

最大生成树类似,答案累加。

代码:

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 1000005
#define N 1000005
#define INF 0x3f3f3f3f
using namespace std;
int cnt,n,m,S,T;
int s,t,v,ans;
struct node
{
    int from,to,val,next;
}edge[M],a[M];
int head[N],dep[N];
void init()
{
    memset(head,-1,sizeof(head)),cnt=0;
}
void edgeadd(int from,int to,int val)
{
    edge[cnt].from=from,edge[cnt].to=to,edge[cnt].val=val,edge[cnt].next=head[from],head[from]=cnt++;
    edge[cnt].from=to,edge[cnt].to=from,edge[cnt].val=0,edge[cnt].next=head[to],head[to]=cnt++;
}
int bfs(int s,int t)
{
    queue<int>q;
    memset(dep,0,sizeof(dep));
    q.push(s),dep[s]=1;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        if(u==t)return 1;
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
            int to=edge[i].to;
            if((!edge[i].val)||dep[to]!=0)continue;
            dep[to]=dep[u]+1;
            q.push(to);
        }
    }
    return 0;
}
int dfs(int s,int max_vale)
{
    int ret=0,tmp;
    if(s==T)return max_vale;
    for(int i=head[s];i!=-1;i=edge[i].next)
    {
        int to=edge[i].to;
        if(dep[to]!=dep[s]+1||edge[i].val==0)continue;
        tmp=dfs(to,min(max_vale-ret,edge[i].val));
        edge[i].val-=tmp;
        edge[i^1].val+=tmp;
        ret+=tmp;
        if(ret==max_vale)return ret;
    }
    return ret;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)scanf("%d%d%d",&a[i].from,&a[i].to,&a[i].val);
    scanf("%d%d%d",&s,&t,&v);
    S=s,T=t;
    init();
    for(int i=1;i<=m;i++)
    {
        if(a[i].val>v)edgeadd(a[i].from,a[i].to,1),edgeadd(a[i].to,a[i].from,1);
    }
    while(bfs(S,T))
        while(int t=dfs(S,INF))
            ans+=t;
    init();
    for(int i=1;i<=m;i++)
    {
        if(a[i].val<v)edgeadd(a[i].from,a[i].to,1),edgeadd(a[i].to,a[i].from,1);
    }
    while(bfs(S,T))
        while(int t=dfs(S,INF))
            ans+=t;
    printf("%d\n",ans);
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

BZOJ 2561 最小生成树 最小割

标签:

原文地址:http://blog.csdn.net/wzq_qwq/article/details/47045203

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!