zoukankan      html  css  js  c++  java
  • [HAOI2017] 新型城市化

    给定一个可以划分为不超过两个团的稠密图,以补图的形式描述。求有多少对点满足在它们之间建边后最大团的大小会增加。(n leq 10^4, m leq 1.5 imes 10^5)

    Solution

    原图的最大团就是补图的最大独立集,由题意补图是二分图,于是转化为求删去哪些边可以使得二分图的最大独立集减少

    考虑到最大独立集数=最大匹配数,于是转化为求哪些边一定在最大匹配里

    定理 二分图的某条边一定在最大匹配中当且仅当这条边满流,且残量网络中这条边的两个顶点不在同一个 SCC 中

    于是我们跑出一个最大匹配,并残量网络并跑 Tarjan,枚举每条匹配边看 SCC 是否相同即可

    注意这里用匈牙利会 T,所以要跑最大流

    由于数据输入时我们不知道哪个点在哪个部,所以要先二分图染色一下

    发现我的强联通板子是假的……

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 200005;
    
    namespace scc {
        vector <int> g[N],scc[N];
        int ind,f[N],siz[N],dfn[N],low[N],vis[N],s[N],bel[N],top,tot,n,m,d[N];
        char ch[N];
        void make(int p,int q) {
            d[q]++;
            g[p].push_back(q);
        }
        void dfs(int p) {
            s[++top]=p;
            dfn[p]=low[p]=++ind;
            for(int i=0;i<g[p].size();i++) {
                int q=g[p][i];
                if(!dfn[q]) dfs(q), low[p]=min(low[p],low[q]);
                else if(!bel[q]) low[p]=min(low[p],dfn[q]);
            }
            if(dfn[p]==low[p]) {
                ++tot;
                for(int i=0;i!=p;) {
                    i=s[top--];
                    bel[i]=tot;
                    scc[tot].push_back(i);
                }
            }
        }
        void solve(int _n) {
            n=_n;
            for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i);
        }
    }
    
    namespace flow {
        const int maxn = 500005;
        const int inf = 1e+9;
        int p1[maxn],p2[maxn],p3[maxn];
        int dis[maxn], ans, cnt = 1, s, t, pre[maxn * 10], nxt[maxn * 10], h[maxn], v[maxn * 10];
        queue<int> q;
        void make(int x, int y, int z) {
            pre[++cnt] = y, nxt[cnt] = h[x], h[x] = cnt, v[cnt] = z;
            p1[cnt]=x; p2[cnt]=y; p3[cnt]=z;
            pre[++cnt] = x, nxt[cnt] = h[y], h[y] = cnt;
            p1[cnt]=y; p2[cnt]=x; p3[cnt]=z;
        }
        bool bfs() {
            memset(dis, 0, sizeof dis);
            q.push(s), dis[s] = 1;
            while (!q.empty()) {
                int x = q.front();
                q.pop();
                for (int i = h[x]; i; i = nxt[i])
                    if (!dis[pre[i]] && v[i])
                        dis[pre[i]] = dis[x] + 1, q.push(pre[i]);
            }
            return dis[t];
        }
        int dfs(int x, int flow) {
            if (x == t || !flow)
                return flow;
            int f = flow;
            for (int i = h[x]; i; i = nxt[i])
                if (v[i] && dis[pre[i]] > dis[x]) {
                    int y = dfs(pre[i], min(v[i], f));
                    f -= y, v[i] -= y, v[i ^ 1] += y;
                    if (!f)
                        return flow;
                }
            if (f == flow)
                dis[x] = -1;
            return flow - f;
        }
        int solve(int _s,int _t) {
            s=_s;
            t=_t;
            ans = 0;
            for (; bfs(); ans += dfs(s, inf));
            return ans;
        }
    }
    
    int n, m, s, t, t1, t2, t3, x[N],y[N];
    int id[N];
    
    struct pii {
        int x,y;
        bool operator < (const pii &b) {
            if(x==b.x) return y<b.y;
            else return x<b.x;
        }
    };
    
    namespace color {
        vector <int> g[N];
        int c[N];
        void make(int p,int q) {
            g[p].push_back(q);
            g[q].push_back(p);
        }
        void dfs(int p) {
            for(int q:g[p]) if(c[q]==0) {
                c[q]=3-c[p];
                dfs(q);
            }
        }
        void solve() {
            for(int i=1;i<=n;i++) {
                if(c[i]==0) {
                    c[i]=1;
                    dfs(i);
                }
            }
        }
    }
    
    int p1[N],p2[N];
    
    int main() {
        ios::sync_with_stdio(false);
        cin>>n>>m;
        for(int i=1;i<=m;i++) {
            cin>>t1>>t2;
            p1[i]=t1;
            p2[i]=t2;
            color::make(t1,t2);
        }
        color::solve();
        for(int i=1;i<=m;i++) {
            t1=p1[i];
            t2=p2[i];
            if(color::c[p1[i]]==2) swap(t1,t2);
            id[i]=flow::cnt+1;
            x[i]=t1;
            y[i]=t2;
            flow::make(t1,t2,1);
        }
        for(int i=1;i<=n;i++) {
            if(color::c[i]==1) flow::make(n+1,i,1);
            else flow::make(i,n+2,1);
        }
        flow::solve(n+1,n+2);
        for(int i=1;i<=flow::cnt;i++) {
            if(flow::v[i]!=0) scc::make(flow::p1[i],flow::p2[i]);
        }
        scc::solve(n+2);
        vector <pii> vec;
        for(int i=1;i<=m;i++) {
            if(flow::v[id[i]]==0) if(scc::bel[x[i]]!=scc::bel[y[i]])
                vec.push_back({min(x[i],y[i]),max(x[i],y[i])});
        }
        cout<<vec.size()<<endl;
        sort(vec.begin(),vec.end());
        for(int i=0;i<vec.size();i++) cout<<vec[i].x<<" "<<vec[i].y<<endl;
    }
    
    
  • 相关阅读:
    phalcon之视图缓存
    Java NIO框架Netty教程(一) – Hello Netty
    setsockopt的作用
    支持向量机通俗导论(理解SVM的三层境地)
    quartz中的corn表达式(转)
    Applet 数字签名技术全然攻略
    SJTU 3001. 二哥的幸运
    OGRE之跳出漫长的编译等待
    VB.NET 数组的定义 动态使用 多维数组
    【Python】用Python的“结巴”模块进行分词
  • 原文地址:https://www.cnblogs.com/mollnn/p/12407497.html
Copyright © 2011-2022 走看看