• 防2B && 图论模板 && 7788


    1.二分图判定染色模板

    bool dfs(int u, int cur){
        col[u]=cur;
        for(int i=0; i<g[u].size(); i++){
            int v=g[u][i];
            if(col[u]==col[v] || (!col[v] && !dfs(v, 3-cur))) return false;
        }
        return true;
    }
    

    2.floyd模板

    void floyd(){                           //求可达性
        int k, i, j;
        for(k=1; k<=n; k++)
            for(i=1; i<=n; i++)
                for(j=1; j<=n; j++) if(!reach[i][j])
                    reach[i][j] = reach[i][j] || (reach[i][k] && reach[k][j]);
    }
    

    3.tarjan 求 割边 / 桥

    void dfs(int u){
        dfn[u]=low[u]=++tsp;
        vis[u]=ins[u]=true;         s.push(u);
        for(int i=h[u]; i!=-1; i=e[i].nxt){
            int v=e[i].v;
            if(!vis[v]){
                ve[e[i].re]=true;
                dfs(v), low[u]=MIN(low[v], low[u]);
                if(dfn[v]==low[v]) ans=MIN(ans, e[i].w);    //割点,割边
            }
            else if(ins[v] && !ve[i]){
                ve[e[i].re]=true;
                low[u]=MIN(dfn[v], low[u]);
            }
        }
        if(dfn[u]==low[u]){             //割点
            int v;
            do{
                v=s.top();      s.pop();
                ins[v]=false;
            }while(v!=u);
        }
    }
     
    void tarjan(){
        int i, j;
        memset(vis, 0, sizeof(vis));
        memset(ve, 0, sizeof(ve));
        memset(ins, 0, sizeof(ins));
        int f=tsp=0;
        for(i=1; i<=n; i++) if(!vis[i])
            dfs(i), f++;
        if(f>1) ans=0;
        if(ans==INF)  ans=-1;
    }
    

     4.tarjan 求强连通分量

    void tarjan(int u){
        dfn[u]=low[u]=++tsp;
        s.push(u);      ins[u]=true;
        int i, v, tl=g[u].size();
        for(i=0; i<tl; i++){
            v=g[u][i];
            if(!dfn[v]) tarjan(v), low[u]=MIN(low[u], low[v]);
            else if(ins[v]) low[u]=MIN(low[u], dfn[v]);             //ins避免横叉边
        }
        if(low[u]==dfn[u]){             //将强连通分量缩为一点
            cnt++;      num[cnt]=0;
       //     cout<<cnt<<endl;
            do{
                v=s.top();      s.pop();
         //       cout<<' '<<v;
                id[v]=cnt;
                ins[v]=false;
                num[cnt]++;
            }while(v!=u);
       //     cout<<"	number:"<<num[cnt]<<endl;
        }
    }
    

     

    5.tarjan 求点双连通分量

    void tarjan(int u, int fa){
        int v, child=0;
        dfn[u]=low[u]=++tsp;
        for(unsigned int i=0; i<g[u].size(); i++){
            v=g[u][i];
            edge t;     t.u=u;      t.v=v;
            if(!dfn[v]){
                child++;
                s.push(t);
                tarjan(v, u);
                low[u]=MIN(low[u], low[v]);
                if(low[v]>=dfn[u]){
                    iscut[u]=1;
                    edge k;
                    bcc[++cnt].clear();
                    while(1){
                        k=s.top();      s.pop();
                        if(id[k.u] != cnt) {id[k.u]=cnt; bcc[cnt].push_back(k.u);}
                        if(id[k.v] != cnt) {id[k.v]=cnt; bcc[cnt].push_back(k.v);}
                        if(k.u==u && k.v==v) break;
                    }
                }
            }
            else if(dfn[v]<dfn[u] && v!=fa) s.push(t), low[u]=MIN(low[u], dfn[v]);
        }
        if(fa<0 && child==1) iscut[u]=0;
    }
    

     

    6.tarjan 边双连通分量

    void tarjan(int u){
        int i,v;
        dfn[u]=low[u]=++tsp;
        s[top++]=u;
        for(i=h[u]; i!=-1; i=e[i].nxt){
            v=e[i].v;
            if(!dfn[v]){
                vis[e[i].re]=1;
                tarjan(v);
                low[u]=MIN(low[u], low[v]);
            }
            else if(!vis[i]) low[u]=MIN(low[u], dfn[v]);        //回边不是反向边,且该点:dfn[v] == low[v]
        }
        if(low[u] == dfn[u]){
            cnt++;
            do{
                v=s[--top];
                id[v]=cnt;              //缩点
            }while(v!=u);
        }
    }
    

     7.稳定婚姻问题 / propose-and-reject algorithm

    void engage(int man, int woman){
        int m=fb[woman];
        if(m) q.push(m), fw[m]=0;           //如果有未婚夫,抛弃
        fw[man]=woman;
        fb[woman]=man;
    }
     
    void solve(){
        memset(fw, 0, sizeof(fw));
        memset(fb, 0, sizeof(fb));
        while(!q.empty()){
            int man=q.front();      q.pop();
            int woman=pref[man][nxt[man]++];
            if(!fb[woman]) engage(man, woman);          //没有未婚夫
            else if(order[woman][fb[woman]]>order[woman][man]) engage(man, woman);   //出现更迷人的汉子
            else q.push(man);
        }
        for(int i=1; i<=n; i++) cout<<manname[i]<<' '<<womanname[fw[i]]<<endl;
    }
    

     (详细见这里:http://www.cnblogs.com/ramanujan/p/3320659.html)

    8.2-sat

    inline void add(int u, int a, int v, int b){            //加边
        u = (u<<1) + a;
        v = (v<<1) + b;
        g[u].push_back(v^1);
        g[v].push_back(u^1);
    }
    
    bool dfs(int u){
        if(mark[u]) return true;                        //如果已标记过
        if(mark[u^1]) return false;                     //如果否命题假设为真,则矛盾
        mark[u]=true;       s[c++]=u;
        int i, tl=g[u].size();
    
        for(i=0; i<tl; i++)
            if(!dfs(g[u][i])) return false;
        return true;
    }
    
    void solve(int n, int ave){
        int i,j;
        memset(mark, 0, sizeof(mark));
        for(i=0; i<n<<1; i+=2) if(!mark[i] && !mark[i+1]){
            c=0;
            if(!dfs(i)){                        //标记i
                while(c--) mark[s[c]]=false;
                if(!dfs(i+1)){                  //标记否命题
                    printf("No solution.
    ");
                    return ;
                }
            }
        }
    }
    

     

    9.扩栈指令(用C++交才有效?):

    #pragma comment(linker,"/STACK:102400000,102400000")
    

    10.Bellman-Ford Algorithm 队列实现

    queue<int> q;
    int bford(int s, int n){
        int u,i,w,v;
        while(!q.empty()) q.pop();  q.push(s);
     //   memset(cnt, 0, sizeof(cnt));    cnt[s]=1;
        memset(inq, 0, sizeof(inq));    inq[s]=1;
        for(i=0; i<n; i++) d[i]=INF;    d[s]=0;
        while(!q.empty()){
            u=q.front();    q.pop();    inq[u]=0;
            for(i=h[u]; i!=-1; i=e[i].nxt){
                v=e[i].v;
                w=e[i].w;
                if(d[v]>d[u]+w){
                    d[v]=d[u]+w;
                    if(!inq[v]){
        //                if(++cnt[v]>n) return 1;
                        q.push(v);
                        inq[v]=1;
                    }
                }
            }
        }
        ans=d[s-1]-d[0];            // 结果不是d[s-1]么?。。。
        return 0;
    }
    

    11.朱刘算法(抄来:http://www.cnblogs.com/nanke/archive/2012/04/11/2441725.html#commentform)

    int mdst(int s, int n, int m){
        int u,v,i,d;
        int ret=0;
        while(true){            //找出每个点的最小入弧
            for(i=0; i<n; i++)
                inv[i]=INF;
            for(i=0; i<m; i++){
                u=e[i].u;
                v=e[i].v;
                d=e[i].d;
                if(d<inv[v] && u!=v){
                    inv[v]=d;   pre[v]=u;
                    if(u==s) roote=i;        //要求的根
                }
            }                               //当前点集合中有点不可达,则图不连通
            for(i=0; i<n; i++) if(inv[i]==INF && i!=s)
                return -1;
            inv[s]=0;
            int cnt=0;
            memset(id, -1, sizeof(id));
            memset(visit, -1, sizeof(visit));
            for(i=0; i<n; i++){                 //缩圈
                ret+=inv[i];
                v=i;                            //如果v还没标记且非虚根
                while(visit[v]!=i && id[v]==-1 && v!=s){
                    visit[v]=i;     v=pre[v];
                }                               //这里表明上步visit[v]=i,即有圈
                if(v!=s && id[v]==-1){
                    for(u=pre[v]; u!=v; u=pre[u])
                        id[u]=cnt;
                    id[v]=cnt++;
                }
            }
            if(!cnt) break;                     //如果没圈
            for(i=0; i<n; i++) if(id[i]==-1)
                id[i]=cnt++;
            for(i=0; i<m; i++){                 //更新缩圈后各边
                u=e[i].u;   v=e[i].v;   d=e[i].d;
                e[i]=(edge){id[u], id[v], (u==v ? d : d-inv[v])};
            }                                   //保证下次迭代选出正确的inv[v]值
            n=cnt;
            s=id[s];
        }
        return ret;
    }
    

    12.欧拉回路

    //判断欧拉回路:
    //1.图是否连通    2.是否存在奇点    3.打印欧拉回路
    void dfs(int s){
        for(int i=1; i<=50; i++) if(g[s][i]){
            g[s][i]--;  g[i][s]--;
            dfs(i);
            ans.push_back((edge){s,i});
        }
    }
    

    13.次小生成树(mst + dfs + 枚举边)

    int p[MAXN];            //并查集
    int finds(int x){
        if(p[x]==-1) return x;
        else return (p[x]=finds(p[x]));
    }
    
    bool vis[MAXM];
    int w[MAXN][MAXN];
    int mst(){              //kruskal
        fill_n(p+1, n, -1);
        fill_n(vis, m, false);
        for(int i=1; i<=n; i++) g[i].clear();
        sort(e, e+m);
    
        int ans=0;
        for(int i=0, j=0; i<m; i++){
            int x = e[i].u, y = e[i].v, d = e[i].d;
            int fx = finds(x), fy = finds(y);
            if(fx!=fy){
                p[fx]=fy;
                ans+=d;                 vis[i]=true;
                g[x].push_back(y);      w[x][y]=w[y][x]=d;
                g[y].push_back(x);              //请用双向边,否则可WAWAWA
                if(++j==n-1) break;
            }
        }
        return ans;
    }
    
    int maxcst[MAXN][MAXN];
    vector<int> pre;
    
    //求mst中任意两点间的最大边权
    void dfs(int u, int fa){
        for(int i=0; i<pre.size(); i++){
            int v = pre[i], d = w[fa][u];
            maxcst[u][v]=maxcst[v][u]=
            MAX(d, maxcst[fa][v]);
        }
        pre.push_back(u);
        for(int i=0; i<g[u].size(); i++) if(fa!=g[u][i])
            dfs(g[u][i], u);
    }
    
    //求mst,次小生成树权值
            int fir = mst();
            for(i=1; i<=n; i++) fill_n(maxcst[i]+1, n, -1);
            pre.clear();
            dfs(1, -1);
            int sec = INF;
            for(i=0; i<m; i++) if(!vis[i]){
                int u = e[i].u, v = e[i].v, d = e[i].d;
                sec=MIN(sec, fir-maxcst[u][v]+d);
            }
            printf("%d %d
    ", fir, sec);        //mst权值,次小生成树权值
    

    14.优先队列优化的 Dijkstra

    void Dijkstra(int s){  
        for(int i=0; i<=mVertex; i++) dis[i]=INF;   dis[s]=0;  
        priority_queue<node> q;   q.push((node){0,s});  
        memset(done, 0, sizeof(done));  
        while(!q.empty()){  
            node t=q.top();     q.pop();  
            int u_ = t.u;  
            if(done[u_]) continue;  done[u_]=true;  
            for(int x=h[u_]; x!=-1; x=next[x]) if(dis[v[x]]-dis[u_]>w[x]){  
                dis[v[x]] = dis[u_] + w[x];  
                p[v[x]] = x;  
                q.push((node){dis[v[x]],v[x]});  
            }  
        }  
    }  
    

    15.2B了再补吧。。。

  • 相关阅读:
    bzoj2243: [SDOI2011]染色
    bzoj4538: [Hnoi2016]网络
    bzoj 1004
    数论小结2.
    数论小结1.
    Catalan Number
    uva 11645
    uva 01510
    redis cluster介绍
    搭建redis-sentinel(哨兵机制)集群
  • 原文地址:https://www.cnblogs.com/ramanujan/p/3364299.html
Copyright © 2020-2023  润新知