• jzoj 5589. 缩点


    Description

    给定一张n个点m条边的无向图。每次你可以选择两个点u,v,将它们合并为一个点w:对于原先的一条边(u,i)或(v,i),连边(w,i);对于原先的一条边(u,u),(v,v)或(u,v),连边(w,w)。每次缩点后图的点数减小1,边数不变。
    求最少需要几次缩点才能使图满足以下条件:(1)不存在重边和简单环,但可以存在自环;(2)存在一条路径使得所有不在路径上的点到它的距离为1。
     

    Input

    第一行两个整数n,m,接下来m行每行三个整数ui,vi表示一条边。保证不存在重边。
    Subtask 1 (10pts):n,m<=10。
    Subtask 2 (36pts):n,m<=2000。
    Subtask 3 (31pts):给定的图是一棵树。
    Subtask 4 (23pts):无特殊限制。
    对于全部数据,1<=n,m<=10^5。

    Output

    输出一行一个整数表示答案。
     

    Sample Input

    输入1:
    4 4
    1 2
    2 3
    3 4
    4 2
    输入2:
    6 3
    1 2
    3 4
    5 6
    输入3:
    7 6
    1 2
    2 3
    1 4
    4 5
    1 6
    6 7

    Sample Output

    输出1:
    2
    输出2:
    2
    输出3:
    1
     

    Code

      

    #include<bits/stdc++.h>
    #define eho(X,x) for(int i=X.head[x];i;i=X.net[i])
    #define v G1.fall[i]
    #define V G2.fall[i]
    #define N 100007
    #define pii pair<int,int>
    using namespace std;
    int n,col[N],nwa[N],nwb[N],cnt,low[N],dfn[N],cn1,usd[N<<1],op;
    map<pii,int> ma;
    struct Graph{
        int tot,head[N],net[N<<1],fall[N<<1];
        Graph() {tot=1;}
        void add(int x,int y){
            fall[++tot]=y; net[tot]=head[x]; head[x]=tot;
        }
        void adds(int x,int y){add(x,y); add(y,x);}
    }G1,G2;
    int s[N],tp;
    int m,x,y,color,ans,us2[N],lef,alg,dis[N],top,he,siz,XX,YY;
    void tarjan(int x,int f) {
        dfn[x]=low[x]=++cnt,s[tp++]=x;
        eho(G1,x) if (v!=f) {if (!dfn[v]) tarjan(v,x);low[x]=min(low[x],low[v]);}
        if (low[x]==dfn[x]) { color++;do {col[s[--tp]]=color;}while (s[tp]!=x);}
    }
    //void tarjan(int x,int f_eg) {
    //    dfn[x]=low[x]=++cnt;
    //    eho(G1,x) {
    //        if (!dfn[v]) {
    //            tarjan(v,i);
    //            low[x]=min(low[x],low[v]);
    //            if (low[v]>low[x]) {
    //             usd[i]=usd[i^1]=1; nwa[++cn1]=G1.fall[i]; nwb[cn1]=G1.fall[i^1];
    //            }
    //        } else if (i^f_eg^1) low[x]=min(low[x],dfn[v]);
    //    }
    //}
    //void dfs(int x,int color) {
    //    col[x]=color;
    //    eho(G1,x) if (!usd[i]&&!col[v]) dfs(v,color);
    //}
    
    void Dfs2(int x,int fa){
        int alg=!!fa;
        us2[x]=1;
        eho(G2,x) if (V^fa) {
            alg++; Dfs2(V,x);
        }
        lef+=alg<=1;
    }
    void Dfs(int x,int fa){
    //    cerr<<x<<endl;
        dis[x]=dis[fa]+1;
        eho(G2,x) if (V^fa) Dfs(V,x); 
        if (dis[x]>dis[top]) top=x;
    }
    void work(int x) {
        lef=0; siz++;
        Dfs2(x,0);
        top=0,Dfs(x,0); he=top;
        top=0,Dfs(he,0); 
        ans+=dis[top]>1?lef+dis[top]-2:1;
        op+=lef;
    }
    signed main () {
        freopen("merge.in","r",stdin);
        freopen("merge.out","w",stdout);
    
        scanf("%d%d",&n,&m);
        for (int i=1;i<=m;i++) {
            scanf("%d%d",&x,&y);
            G1.adds(x,y);
        }
        for (int i=1;i<=n;i++) if (!dfn[i]) tarjan(i,0);
    //    for (int i=1;i<=n;i++) {
    //        if (col[i]) continue;
    //        dfs(i,++color);
    //    } 
        int pi=0;
    //    assert(p)
    //    for (int i=1;i<=cn1;i++)  {
    //       XX=col[nwa[i]]; YY=col[nwb[i]];
    //       if (XX>YY) swap(XX,YY);
    //       if (ma.count(pii(XX,YY))) continue;
    //       G2.adds(XX,YY);
    //       ma[pii(XX,YY)]=1; pi++;
    //    }
    //    assert(cn1==pi);
        for (int j=1;j<=n;j++) eho(G1,j) if (col[j]!=col[v]) G2.add(col[j],col[v]),pi++;
    //    cerr<<pi<<endl;
        for (int i=1;i<=color;i++)  if (!us2[i]) work(i);
        printf("%d
    ",n-ans+siz-1);
    //    cerr<<pi/2+siz<<endl;
        cerr<<op<<endl;
    //    assert(pi+siz-1==color);
        return 0;
    }
     
  • 相关阅读:
    leetcode165
    leetcode63
    leetcode92
    leetcode86
    捣鼓Haskell
    递归操作链表
    treap(堆树)
    贪心策略 — 分数背包
    LeetCode.21
    LeetCode.94
  • 原文地址:https://www.cnblogs.com/rrsb/p/9878888.html
Copyright © 2020-2023  润新知