Luogu3731 HAOI2017新型城市化(二分图匹配+强连通分量)

  将未建立贸易关系看成连一条边,那么这显然是个二分图。最大城市群即最大独立集,也即n-最大匹配。现在要求的就是删哪些边会使最大匹配减少,也即求哪些边一定在最大匹配中。

  首先范围有点大,当然是跑个dinic,转化成最大流。会使最大流减少的边相当于可能在最小割中的边,因为删掉它就相当于无代价的割掉了一条边。那么用曾经看到过的结论就可以了:当且仅当该边满流且残余网络(包括反向边)中该边两端点处于不同SCC时,该边可能在最小割中。不太会证。于是tarjan一发就可以了。注意不要把开始给的图和网络流建图搞混。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 10010
#define M 300010
#define S 0
#define T 10001
char getc(){char c=getchar();while (c==10||c==13||c==32) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<‘0‘||c>‘9‘) {if (c==‘-‘) f=-1;c=getchar();}
    while (c>=‘0‘&&c<=‘9‘) x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
int n,m,p[N],t=-1,color[N],ans;
int d[N],q[N],cur[N];
struct data{int to,nxt,cap,flow;
}edge[M<<1];
struct data2
{
    int x,y;
    bool operator <(const data2&a) const
    {
        return x<a.x||x==a.x&&y<a.y;
    }
}v[M];
void addedge(int x,int y,int z)
{
    t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].cap=z,edge[t].flow=0,p[x]=t;
    t++;edge[t].to=x,edge[t].nxt=p[y],edge[t].cap=0,edge[t].flow=0,p[y]=t;
}
void paint(int k)
{
    for (int i=p[k];~i;i=edge[i].nxt)
    if (color[edge[i].to]==-1)
    {
        color[edge[i].to]=color[k]^1;
        paint(edge[i].to);
    }
}
bool bfs()
{
    int head=0,tail=1;q[1]=S;
    memset(d,255,sizeof(d));d[S]=0;
    do
    {
        int x=q[++head];
        for (int i=p[x];~i;i=edge[i].nxt)
        if (d[edge[i].to]==-1&&edge[i].flow<edge[i].cap)
        {
            d[edge[i].to]=d[x]+1;
            q[++tail]=edge[i].to;
        }
    }while (head<tail);
    return ~d[T];
}
int work(int k,int f)
{
    if (k==T) return f;
    int used=0;
    for (int i=cur[k];~i;i=edge[i].nxt)
    if (d[k]+1==d[edge[i].to])
    {
        int w=work(edge[i].to,min(f-used,edge[i].cap-edge[i].flow));
        edge[i].flow+=w,edge[i^1].flow-=w;
        if (edge[i].flow<edge[i].cap) cur[k]=i;
        used+=w;if (used==f) return f;
    }
    if (used==0) d[k]=-1;
    return used;
}
void dinic()
{
    while (bfs())
    {
        memcpy(cur,p,sizeof(p));
        work(S,N);
    }
}
namespace newgraph
{
    int dfn[N]={0},low[N]={0},stk[N],id[N],top=0,cnt=0,tot=0,t=0,p[N]={0},ans=0;
    bool flag[N];
    struct data{int to,nxt;}edge[M];
    void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
    void tarjan(int k)
    {
        dfn[k]=low[k]=++cnt;
        stk[++top]=k;flag[k]=1;
        for (int i=p[k];i;i=edge[i].nxt)
        if (!dfn[edge[i].to]) tarjan(edge[i].to),low[k]=min(low[k],low[edge[i].to]);
        else if (flag[edge[i].to]) low[k]=min(low[k],dfn[edge[i].to]);
        if (dfn[k]==low[k])
        {
            tot++;
            while (stk[top]!=k)
            {
                flag[stk[top]]=0;
                id[stk[top]]=tot;
                top--;
            }
            flag[k]=0;id[k]=tot;top--;
        }
    }
    void work()
    {
        for (int i=0;i<=n;i++)
        if (!dfn[i]) tarjan(i);
        if (!dfn[T]) tarjan(T);
    }
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    const char LL[]="%I64d\n";
#else
    const char LL[]="%lld\n";
#endif
    n=read(),m=read();
    memset(p,255,sizeof(p));
    for (int i=1;i<=m;i++)
    {
        int x=read(),y=read();
        addedge(x,y,1);
    }
    memset(color,255,sizeof(color));
    for (int i=1;i<=n;i++) if (color[i]==-1) color[i]=1,paint(i);
    for (int i=0;i<=t;i++) edge[i].cap=color[edge[i^1].to];
    for (int i=1;i<=n;i++)
    if (color[i]) addedge(S,i,1);
    else addedge(i,T,1);
    dinic();
    for (int i=0;i<=t;i++)
    if (edge[i].flow<edge[i].cap) newgraph::addedge(edge[i^1].to,edge[i].to);
    newgraph::work();
    for (int i=0;i<=t;i++)
    if (edge[i].cap==1&&edge[i].flow==edge[i].cap&&edge[i^1].to!=S&&edge[i].to!=T&&newgraph::id[edge[i^1].to]!=newgraph::id[edge[i].to])
    ans++,v[ans].x=min(edge[i^1].to,edge[i].to),v[ans].y=max(edge[i^1].to,edge[i].to);
    sort(v+1,v+ans+1);
    cout<<ans<<endl;
    for (int i=1;i<=ans;i++) printf("%d %d\n",v[i].x,v[i].y);
    return 0;
}

原文地址:https://www.cnblogs.com/Gloid/p/9919199.html

时间: 2024-10-29 13:36:21

Luogu3731 HAOI2017新型城市化(二分图匹配+强连通分量)的相关文章

UESTC 898 方老师和缘分 --二分图匹配+强连通分量

这题原来以为是某种匹配问题,后来好像说是强连通的问题. 做法:建图,每个方老师和它想要的缘分之间连一条有向边,然后,在给出的初始匹配中反向建边,即如果第i个方老师现在找到的是缘分u,则建边u->i.这样求出所有的强连通分量,每个强连通分量中方老师和缘分的数目一定是相等的,所以每个方老师一定可以找到与他在同一个强连通分量里的缘分,因为强连通分量中每个点都是可达的,某个方老师找到了其强连通分量中的非原配点,则该原配缘分一定可以在强连通分量中找到"新欢".可以画个图看看. 由于要构造非

poj1904 二分图匹配+强连通分量

http://poj.org/problem?id=1904 Description Once upon a time there lived a king and he had N sons. And there were N beautiful girls in the kingdom and the king knew about each of his sons which of those girls he did like. The sons of the king were you

【连通图|二分匹配+强连通分量】POJ-1904 King&#39;s Quest

King's Quest Time Limit: 15000MS Memory Limit: 65536K Case Time Limit: 2000MS Description Once upon a time there lived a king and he had N sons. And there were N beautiful girls in the kingdom and the king knew about each of his sons which of those g

洛谷 P3731 [HAOI2017]新型城市化【最大流(二分图匹配)+tarjan】

我到底怎么建的图为啥要开这么大的数组啊?! 神题神题,本来以为图论出不出什么花来了. 首先要理解'团'的概念,简单来说就是无向图的一个完全子图,相关概念详见度娘. 所以关于团一般都是NP问题,只有二分图例外.而题目中有这样一句话"n座城市可以恰好被划分为不超过两个城市群",并且给出的是没有的边,也就是这个图的补图,两个团就很显然表示这个补图是个二分图(我一开始还考虑1个团咋整后来发现根本不用整= =),模型就变成了二分图的最大独立集,考虑最大独立集=n-最大匹配,那么只要求出删掉哪些边

[HAOI2017]新型城市化

题目描述 Anihc国有n座城市.城市之间存在若一些贸易合作关系.如果城市x与城市y之间存在贸易协定.那么城市文和城市y则是一对贸易伙伴(注意:(x,y)和(y,x))是同一对城市). 为了实现新型城市化.实现统筹城乡一体化以及发挥城市群辐射与带动作用.国 决定规划新型城市关系.一些城市能够被称为城市群的条件是:这些城市两两都是贸易伙伴. 由于Anihc国之前也一直很重视城市关系建设.所以可以保证在目前已存在的贸易合作关系的情况下Anihc的n座城市可以恰好被划分为不超过两个城市群. 为了建设新

[HAOI2017] 新型城市化 - 强联通分量,最大流,二分图染色

给定一个可以划分为不超过两个团的稠密图,以补图的形式描述.求有多少对点满足在它们之间建边后最大团的大小会增加.\(n \leq 10^4, m \leq 1.5\times 10^5\) Solution 原图的最大团就是补图的最大独立集,由题意补图是二分图,于是转化为求删去哪些边可以使得二分图的最大独立集减少 考虑到最大独立集数=最大匹配数,于是转化为求哪些边一定在最大匹配里 定理 二分图的某条边一定在最大匹配中当且仅当这条边满流,且残量网络中这条边的两个顶点不在同一个 SCC 中 于是我们跑

H - Prince and Princess - HDU 4685(二分匹配+强连通分量)

题意:有N个王子M个公主,王子喜欢一些公主,而且只能是王子喜欢的人,他们才可以结婚,现在让他们尽可能多的结婚的前提下找出来每个王子都可以和谁结婚. 分析:先求出来他们的最大匹配,因为给的数据未必是完备匹配,所以需要添加一些点使他们成为完备匹配才能求出来的环是完整的,比如第二组数据: 1 2   2 1 2 如果不添加虚拟点做成匹配,只会匹配成功一个,这样就找不出来环了,所以需要添加虚拟的王子和公主,虚拟的王子喜欢所有的公主,虚拟的公主被所有的王子喜欢,注意都是王子喜欢公主的,公主没有选择喜欢的权

hdu 4685 二分匹配+强连通分量

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4685 题解: 1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<vector> 5 #include<stack> 6 #include<algorithm> 7 using namespace std; 8 9 const int maxn =

POJ - 1904 King&#39;s Quest(强连通分量+二分图匹配)

题目大意:有N个帅哥和N个美女,现在给出每个帅哥所喜欢的美女的编号,和一个帅哥和美女的完美匹配 问每个帅哥可以娶多少个美女,且当他娶完这个美女后,剩下的人还可以完美匹配 解题思路:神题啊,给一个大神的详细解答 具体是这样的,首先先建边,把帅哥和能娶到的美女连边,再把完美匹配的美女和帅哥连边,这样就形成了一张有向图了 接着,找出这张有向图的所有强连通分量,在强连通分量里面的帅哥都可以娶到自己喜欢的美女,且娶完这个美女后,不会影响到其他人 为什么呢? 假设xi为帅哥,yi和yj为美女,假设给定的完美