洛谷 P3731 [HAOI2017]新型城市化

博客介绍了洛谷P3731题目的解决方案,强调图的补图一定是二分图,最大团等价于最大独立集,可以通过寻找最小割来解决问题。提醒在处理网络流问题时,不应随意设置边的上界,并提供了相关题目链接和解题思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

原题链接
给定一张图,这张图最多有两个团,求增加一条边使得最大团变大。

分析

再也不乱给边加上界了啊啊啊啊!!!

这张图的补图一定是二分图。

其中最大团就是最大独立集。

最大独立集就是结点数-最大流

我们要最大流减少

所以我们要找最小割

按照BZOJ 1797: [Ahoi2009]Mincut 最小割(我的博客)第一问的方法判断一个结点是否是一种最小割里面的一个点就可以了。

二分图千万反向边千万不要偷懒使得上界和正向边相同。
网络流都不要偷懒乱加上界!

代码

#include<cmath>
#include<queue>
#include<cctype>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=10000+105,maxm=15e4+105,inf=1e8;
int np,first[maxn];
struct edge{
    int from,to,next,cap,flow;
}E[maxm<<1];
void add(int u,int v,int c)
{
    E[++np]=(edge){u,v,first[u],c,0};
    first[u]=np;
}
int n,m,s,t;
void Init()
{
    int u,v;
    np=-1;
    memset(first,-1,sizeof(first));
    scanf("%d%d",&n,&m);
    s=n+1,t=s+1;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&u,&v);
        add(u,v,1);
        add(v,u,1);
    }
}
int dist[maxn],gap[maxn];
int SAP(int i,int lim)
{
    if(i==t)return lim;
    int flow=0,tmp;
    for(int p=first[i];p!=-1;p=E[p].next)if(E[p].cap-E[p].flow)
    {
        int j=E[p].to;
        if(dist[i]==dist[j]+1)
        {
            tmp=SAP(j,min(lim-flow,E[p].cap-E[p].flow));
            E[p].flow+=tmp;
            E[p^1].flow-=tmp;
            flow+=tmp;
            if(dist[s]>=t || lim==flow)return flow;
        }
    }
    if(flow==0)
    {
        if(--gap[dist[i]]==0)dist[s]=t;
        gap[++dist[i]]++;
    }
    return flow;
}
void maxFlow()
{
    memset(gap,0,sizeof(gap));
    memset(dist,0,sizeof(dist));
    gap[0]=t;
    while(dist[s]<t)SAP(s,inf);
}
int stk[maxn],top;
int dfs_clock,scc,belong[maxn],low[maxn],dfn[maxn];
void DFS(int i)
{
    stk[++top]=i;
    dfn[i]=low[i]=++dfs_clock;
    for(int p=first[i];p!=-1;p=E[p].next)
    {
        if(E[p].cap-E[p].flow)
        {
            int j=E[p].to;
            if(belong[j])continue;
            if(dfn[j])
            {
                low[i]=min(low[i],low[j]);
                continue;
            }
            DFS(j);
            low[i]=min(low[j],low[i]);
        }
    }
    if(dfn[i]==low[i])
    {
        int x;
        scc++;
        while(1)
        {
            x=stk[top--];
            belong[x]=scc;
            if(x==i)break;
        }
    }
}
void tarjian()
{
    for(int i=1;i<=t;i++)
        if(!dfn[i])DFS(i);
}
struct data
{
    int i,j;
    friend bool operator<(data a,data b)
    {
        return a.i!=b.i?a.i<b.i:a.j<b.j;
    }
    void outs()
    {
        printf("%d %d\n",i,j);
    }
}ans[maxn];
int cnt;
void query()
{
    for(int i=1;i<=n;i++)
    {
        for(int p=first[i];p!=-1;p=E[p].next)
        {
            if(E[p].flow)
            {
                int j=E[p].to;
                if(j<i)continue;
                if(j==s || j==t)continue;
                if(belong[i] != belong[j])
                    ans[++cnt]=(data){i,j};
            }
        }
    }
    sort(ans+1,ans+cnt+1);
    printf("%d\n",cnt);
    for(int i=1;i<=cnt;i++)
        ans[i].outs();
}
bool vis[maxn],co[maxn];
void DFS(int i,bool c)
{
    co[i]=c;
    vis[i]=1;
    if(c)
    {
        add(s,i,1);
        add(i,s,0);
    }
    else
    {
        add(i,t,1);
        add(t,i,0);
    }
    for(int p=first[i];p!=-1;p=E[p].next)
    {
        int j=E[p].to;
        if(vis[j] || j==s || j==t)continue;
        DFS(j,c^1);
    }
}
void erfen()
{
    for(int i=1;i<=n;i++)if(!vis[i])DFS(i,1);
    for(int i=1;i<=m;i++)
    {
        int j=E[(i-1)*2].to;
        (!co[E[(i-1)*2].from] && co[j])?E[(i-1)*2].cap=0:E[((i-1)*2)^1].cap=0;
    }
}
int main()
{
    //freopen("in.txt","r",stdin);
    Init();
    erfen();
    maxFlow();
    tarjian();
    query();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值