[HAOI2017]新型城市化

Posted ~victorique~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[HAOI2017]新型城市化相关的知识,希望对你有一定的参考价值。

题目描述

Anihc国有n座城市.城市之间存在若一些贸易合作关系.如果城市x与城市y之间存在贸易协定.那么城市文和城市y则是一对贸易伙伴(注意:(x,y)和(y,x))是同一对城市)。

为了实现新型城市化.实现统筹城乡一体化以及发挥城市群辐射与带动作用.国 决定规划新型城市关系。一些城市能够被称为城市群的条件是:这些城市两两都是贸易伙伴。 由于Anihc国之前也一直很重视城市关系建设.所以可以保证在目前已存在的贸易合作关系的情况下Anihc的n座城市可以恰好被划分为不超过两个城市群。

为了建设新型城市关系Anihc国想要选出两个之前并不是贸易伙伴的城市.使这两个城市成为贸易伙伴.并且要求在这两个城市成为贸易伙伴之后.最大城市群的大小至少比他们成为贸易伙伴之前的最大城市群的大小增加1。

Anihc国需要在下一次会议上讨论扩大建设新型城市关系的问题.所以要请你求出在哪些城市之间建立贸易伙伴关系可以使得这个条件成立.即建立此关系前后的最大城市群的 大小至少相差1。

输入输出格式

输入格式:

第一行2个整数n,m.表示城市的个数,目前还没有建立贸易伙伴关系的城市的对数。

接下来m行,每行2个整数x,y表示城市x,y之间目前还没有建立贸易伙伴关系。

输出格式:

第一行yi个整数ans,表示符合条件的城市的对数.注意(x,y)与(y,x)算同一对城市。

接下来Ans行,每行两个整数,表示一对可以选择来建立贸易伙伴关系的城市。对于 一对城市x,y请先输出编号更小的那一个。最后城市对与城市对之间顺序请按照字典序从小到大输出。

输入输出样例

输入样例#1:

5 3
1 5
2 4
2 5

输出样例#1:

2
1 5
2 4

说明

数据规模与约定

数据点1: n≤16

数据点2: n≤16

数据点3~5: n≤100

数据点6: n≤500

数据点7~10: n≤10000

对于所有的数据保证:n <= 10000,0 <= m <= min (150000,n(n-1)/2).保证输入的城市关系中不会出现(x,x)这样的关系.同一对城市也不会出现两次(无重边.无自环)。

Solution

单纯想练习码力的可以看一句话题意解释,一个二分图,求删去那些边可以是二分图的最大独立集的大小+1.

BZOJ暂时没有这个题。。以为网络流的骚操作也弄得差不多了,然而还是自己太naive了。

看看这个题目,首先给出的样例和输入方式特别像,一个图。。。所以我们就把这些边都连起来。。然后我们根据题意可以发现,如果一堆城市属于一个城市群,那么这些城市之间彼此都不会连边。那么按照我刚才的连边方法,就出来一个二分图。那么最大的城市群就是最大的的独立集,建立关系就是删去图中的一条边,那么因为:最大独立集=总点数-最小覆盖集 可以得出我们要求的就是删去图中的那些边可以使这个图的最大匹配增加1。

那么这个题就比较显而易见了,可以先跑一遍网络流,然后再一遍枚举一边一遍一遍的跑网络流。。。不过这题数据范围最多也就过到5个点吧。然后根据定理:若一条边一定在最大匹配中,则在最终的残量网络中,这条边一定满流,且这条边的两个顶点一定不在同一个强连通分量中。 可以跑Tarjan搞一搞,然后暴力枚举边来判断就行。证明网上搜搜应该能有,这里不给出了。‘

Code

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <set>
#include <map>
#define MAXN 200000
#define re register
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define ms(arr) memset(arr, 0, sizeof(arr))
const int inf = 0x3f3f3f3f;
struct po
{
    int nxt,to,w,from;    
}edge[250001];
struct ANS
{
    int x,y;
}ans[MAXN];
int n,m,cur[MAXN],head[20002],num=-1,dep[20002],s,t,c[MAXN],vis[20002];
inline int read()
{
    int x=0,c=1;
    char ch=' ';
    while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();
    while(ch=='-') c*=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-'0',ch=getchar();
    return x*c;
}
inline void add_edge(int from,int to,int w)
{
    edge[++num].nxt=head[from];
    edge[num].from=from;
    edge[num].to=to;
    edge[num].w=w;
    head[from]=num;
}
inline void add(int from,int to,int w)
{
    add_edge(from,to,w);
    add_edge(to,from,0);
}
inline bool bfs()
{
    memset(dep,0,sizeof(dep));
    queue<int> q;
    while(!q.empty())
    q.pop();
    q.push(s);
    dep[s]=1;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(re int i=head[u];i!=-1;i=edge[i].nxt)
        {
            int v=edge[i].to;
            if(dep[v]==0&&edge[i].w>0)
            {
                dep[v]=dep[u]+1;
                if(v==t)
                return 1;
                q.push(v);
            }
        }
    }
    return 0;
}
inline int dfs(int u,int dis)
{
    if(u==t)
    return dis;
    int diss=0;
    for(re int& i=cur[u];i!=-1;i=edge[i].nxt)
    {
        int v=edge[i].to;
        if(edge[i].w!=0&&dep[v]==dep[u]+1)
        {
            int check=dfs(v,min(dis,edge[i].w));
            if(check!=0)
            {
                dis-=check;
                diss+=check;
                edge[i].w-=check;
                edge[i^1].w+=check;
                if(dis==0) break;
            }
        }
    }
    return diss;
}
inline void dinic()
{
    while(bfs())
    {
        for(re int i=s;i<=t;i++)
        cur[i]=head[i];
        while(int d=dfs(s,inf));
    }
}
void put_color(int u,int col)
{
    c[u]=col;
    vis[u]=1;
    for(re int i=head[u];i!=-1;i=edge[i].nxt){
        int v=edge[i].to;
        if(!vis[v]) put_color(v,col^1);
    }
}
int dfn[MAXN],low[MAXN],stack[MAXN],color_num,color[MAXN],cnt,top;
inline void Tarjan(int u)
{
    dfn[u]=low[u]=++cnt;
    vis[u]=1;
    stack[++top]=u;
    for(re int i=head[u];i!=-1;i=edge[i].nxt){
        if(!edge[i].w){
            int v=edge[i].to;
            if(!dfn[v]){
                Tarjan(v);
                low[u]=min(low[u],low[v]);
            } else if(vis[v]) low[u]=min(low[u],dfn[v]);
        }
    }
    if(dfn[u]==low[u]){
        color[u]=++color_num;
        vis[u]=0;
        while(stack[top]!=u){
            color[stack[top]]=color_num;
            vis[stack[top--]]=0;
        }
        top--;
    }
}
int x[MAXN],y[MAXN],tot;
inline bool cmp(ANS a,ANS b){
    return a.x==b.x?a.y<b.y:a.x<b.x;
}
int main() 
{
    memset(head,-1,sizeof(head));
    n=read();m=read();
    for(re int i=1;i<=m;i++){
        x[i]=read();y[i]=read();
        add_edge(x[i],y[i],0);
        add_edge(y[i],x[i],1);
    }
    
    for(re int i=1;i<=n;i++)
        if(!vis[i]) put_color(i,2);
    memset(head,-1,sizeof(head));
    s=0,t=n+1;num=-1;
    for(re int i=1;i<=n;i++){
        if(c[i]==2)
            add(s,i,1);
        else add(i,t,1);
    }
    for(re int i=1;i<=m;i++){
        if(c[x[i]]==2)
            add(x[i],y[i],1);
        else add(y[i],x[i],1);
    }
    dinic();
    memset(vis,0,sizeof(0));
    for(re int i=1;i<=n;i++)
        if(!dfn[i]) Tarjan(i);
    for(re int i=0;i<=num;i+=2){
        int u=edge[i].from,v=edge[i].to;
        if(!edge[i].w&&color[u]!=color[v]&&u!=s&&v!=t&&u!=t&&v!=s){
            if(u>v) swap(u,v);
            ans[++tot].x=u;ans[tot].y=v;
        }
    }
    
    sort(ans+1,ans+tot+1,cmp);
    cout<<tot<<endl;
    for(re int i=1;i<=tot;i++)
        printf("%d %d\n", ans[i].x,ans[i].y);
    return 0;
}
/*6 5 3 7 2 4 1*/

以上是关于[HAOI2017]新型城市化的主要内容,如果未能解决你的问题,请参考以下文章

HAOI2017 新型城市化

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

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

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

线段树分治 线性基luoguP3733 [HAOI2017]八纵八横

415. [HAOI2009] 旅行