• 图论


    最短路:

    //权值非负,不连通为INF、
    //O(n^2)
    void dij(int beg)
    {
        memset(dis,0x3f,sizeof(dis));
        memset(vis,0,sizeof(vis));
        dis[beg] = 0;
        for(int i = 1;i <= n;i++)
        {
            int k = -1,minn = INF;
            for(int j = 1;j <= n;j++)
            {
                if(!vis[j] && dis[j] < minn)
                {
                    minn = dis[j];
                    k = j;
                }
            }
            if(k == -1) break;
            vis[k] = 1;
            for(int j = 1;j <= n;j++)
            {
                if(!vis[j] && dis[k]+a[k][j] < dis[j])
                {
                    dis[j] = dis[k]+a[k][j];
                }
            }
        }
    }
    dij邻接矩阵
    ///O(mlogm)
    struct xxx
    {
        int to,w;
        xxx(int a,int b):to(a),w(b){};
        friend bool operator <(xxx X,xxx Y)
        {
            return X.w > Y.w;
        }
    };
    
    void dij(int beg)
    {
        priority_queue<xxx> q;
        memset(dis,0x3f,sizeof(dis));
        memset(vis,0,sizeof(vis));
        dis[beg] = 0;
        q.push(xxx(beg,0));
        while(!q.empty())
        {
            int now = q.top().to;
            q.pop();
            if(vis[now])    continue;
            vis[now] = 1;
            for(int i = 0;i < v[now].size();i++)
            {
                int t = v[now][i].to,w = v[now][i].w;
                if(!vis[t] && dis[now]+w < dis[t])
                {
                    dis[t] = dis[now]+w;
                    q.push(xxx(t,dis[t]));
                }
            }
        }
    }
    dij优先队列
    //O(n^3)
    void floyd()
    {
        for(int k = 0;k < n;k++)
        {
            for(int i = 0;i < n;i++)
            {
                for(int j = 0;j < n;j++)    a[i][j] = min(a[i][j],a[i][k]+a[k][j]);
            }
        }
    }
    floyd
    //v储存所有边
    //O(nm)
    struct xxx
    {
        int u,v,w;
        xxx(int a,int b,int c):u(a),v(b),w(c){};
    };
    vector<xxx> v;
    
    //存在负环返回0,否则返回1
    bool bellman_ford(int beg)
    {
        memset(dis,0x3f,sizeof(dis));
        dis[beg] = 0;
        for(int i = 1;i < n;i++)
        {
            for(int j = 0;j < v.size();j++)
            {
                int x = v[j].u,y = v[j].v,w = v[j].w;
                dis[y] = min(dis[y],dis[x]+w);
            }
        }
        for(int i = 0;i < v.size();i++)
        {
            int x = v[i].u,y = v[i].v,w = v[i].w;
            if(dis[y] > dis[x]+w)   return 0;
        }
        return 1;
    }
    bellman_ford
    //O(km)
    struct xxx
    {
        int to,w;
        xxx(int a,int b):to(a),w(b){};
    };
    vector<xxx> v[205];
    
    //存在负环返回0,否则返回1
    bool spfa(int beg)
    {
        queue<int> q;
        memset(c,0,sizeof(c));
        memset(vis,0,sizeof(vis));
        memset(dis,0x3f,sizeof(dis));
        dis[beg] = 0;
        q.push(beg);
        vis[beg] = 1;
        c[beg] = 1;
        while(!q.empty())
        {
            int now = q.front();
            q.pop();
            vis[now] = 0;
            for(int i = 0;i < v[now].size();i++)
            {
                int t = v[now][i].to,w = v[now][i].w;
                if(dis[now]+w < dis[t])
                {
                    dis[t] = dis[now]+w;
                    vis[t] = 1;
                    q.push(t);
                    if(++c[t] > n)   return 0;
                }
            }
        }
        return 1;
    }
    spfa
    #include<bits/stdc++.h>
    #define INF 0x3f3f3f3f
    using namespace std;
    
    struct xxx
    {
        int to,w;
        xxx(int a,int b):to(a),w(b){};
        friend bool operator<(xxx x,xxx y)
        {
            return x.w > y.w;
        }
    };
    vector<xxx> v[11005];
    int n,m,k,a[1005][1005],dis[11005],vis[11005];
    
    void dij(int beg)
    {
        memset(dis,0x3f,sizeof(dis));
        memset(vis,0,sizeof(vis));
        priority_queue<xxx> q;
        dis[beg] = 0;
        q.push(xxx(beg,0));
        while(!q.empty())
        {
            int now = q.top().to;
            q.pop();
            if(vis[now])    continue;
            vis[now] = 1;
            for(int i = 0;i < v[now].size();i++)
            {
                int t = v[now][i].to,w = v[now][i].w;
                if(w+dis[now] < dis[t])
                {
                    dis[t] = w+dis[now];
                    q.push(xxx(t,dis[t]));
                }
            }
    
        }
    }
    
    int main()
    {
        while(~scanf("%d%d%d",&n,&m,&k))
        {
            for(int i = 1;i <= 11000;i++)    v[i].clear();
            memset(a,0x3f,sizeof(a));
            for(int i = 1;i <= m;i++)
            {
                int u,v,w;
                scanf("%d%d%d",&u,&v,&w);
                a[u][v] = min(a[u][v],w);
                a[v][u] = min(a[v][u],w);
            }
            for(int i = 1;i <= n;i++)
            {
                for(int j = 1;j <= n;j++)
                {
                    if(i == j || a[i][j] == INF)    continue;
                    for(int l = 0;l <= k;l++)
                    {
                        v[l*n+i].push_back(xxx(l*n+j,a[i][j]));
                        if(l != k)
                        {
                            v[l*n+i].push_back(xxx((l+1)*n+j,0));
                        }
                    }
                }
            }
            dij(1);
            printf("%d
    ",dis[(k+1)*n]);
        }
        return 0;
    }
    分层图最短路

    最小生成树:

    //不连通返回-1,否则返回最小花费
    int prim()
    {
        int ans = 0;
        memset(vis,0,sizeof(vis));
        vis[1] = 1;
        for(int i = 2;i <= n;i++)   cost[i] = a[1][i];
        for(int i = 2;i <= n;i++)
        {
            int minn = INF;
            int k = -1;
            for(int j = 1;j <= n;j++)
            {
                if(!vis[j] && minn > cost[j])
                {
                    minn = cost[j];
                    k = j;
                }
            }
            if(minn == INF) return -1;
            ans += minn;
            vis[k] = 1;
            for(int j = 1;j <= n;j++)
            {
                if(!vis[j] && cost[j] > a[k][j])    cost[j] = a[k][j];
            }
        }
        return ans;
    }
    prim邻接矩阵
    struct xxx
    {
        int to,w;
        xxx(int a,int b):to(a),w(b){}
        friend bool operator<(xxx a,xxx b)
        {
            return a.w > b.w;
        }
    };
    //非连通返回-1,否则返回最小花费
    int prim()
    {
        memset(vis,0,sizeof(vis));
        for(int i = 0;i < n;i++)    dis[i] = INT_MAX;
        int ans = 0;
        priority_queue<xxx> q;
        q.push(xxx(1,0));
        while(!q.empty())
        {
            while(!q.empty() && vis[q.top().to])    q.pop();
            if(q.empty())   break;
            ans += q.top().w;
            int now = q.top().to;
            q.pop();
            vis[now] = 1;
            for(int i = 0;i < v[now].size();i++)
            {
                int t = v[now][i].to,w = v[now][i].w;
                if(vis[t])  continue;
                if(dis[t] <= w) continue;
                dis[t] = w;
                q.push(xxx(t,w));
            }
        }
        return ans;
    }
    prim优先队列
    struct xxx
    {
        int from,to,w;
        xxx(int a,int b,int c):from(a),to(b),w(c){};
        friend bool operator <(xxx a,xxx b)
        {
            return a.w < b.w;
        }
    };
    vector<xxx> v;
    
    int findd(int x)
    {
        return pre[x] == x?x:findd(pre[x]);
    }
    
    //不连通返回-1,否则返回最小花费
    bool kruskal()
    {
        for(int i = 1;i <= n;i++)   pre[i] = i;
        int ans = 0,cnt = 0;
        sort(v.begin(),v.end());
        for(int i = 0;i < v.size();i++)
        {
            int x = findd(v[i].from),y = findd(v[i].to);
            if(x != y)
            {
                ans += v[i].w;
                pre[x] = y;
                cnt++;
            }
        }
        if(cnt < n-1)   return -1;
        return ans;
    }
    kruskal

    矩阵树定理:

    1.G的度数矩阵D[G]是一个n*n的矩阵,并且满足:当i≠j时,dij=0;当i=j时,dij等于vi的度数。

    2.G的邻接矩阵A[G]也是一个n*n的矩阵, 并且满足:如果vi、vj之间有边直接相连,则aij=1,否则为0。

    3.G的Kirchhoff矩阵(也称为拉普拉斯算子)C[G]=D[G]-A[G]。

    则G的生成树个数等于C[G]任何一个n-1阶主子式的行列式的绝对值。

    #include<bits/stdc++.h>
    using namespace std;
    
    int n,m,k,a[55][55];
    long long g[55][55]; 
    
    long long calc()
    {
        long long ans = 1;
        for(int i = 1;i < n;i++)
        {
            for(int j = i+1;j < n;j++)
            {
                while(g[j][i] != 0)
                {
                    long long t = g[i][i]/g[j][i];
                    for(int k = i;k < n;k++)    g[i][k] -= t*g[j][k];
                    for(int k = i;k < n;k++)    swap(g[i][k],g[j][k]);
                    ans = -ans;
                }
            }
            if(g[i][i] == 0)    return 0;
            ans = ans*g[i][i];
        }
        return abs(ans);
    }
    
    int main()
    {
        ios::sync_with_stdio(false);
        while(cin >> n >> m >> k)
        {
            memset(a,0,sizeof(a));
            memset(g,0,sizeof(g));
            while(m--)
            {
                int x,y;
                cin >> x >> y;
                a[x][y] = a[y][x] = 1;
            }
            for(int i = 1;i <= n;i++)
            {
                int t = 0;
                for(int j = 1;j <= n;j++)
                {
                    if(i != j && !a[i][j])
                    {
                        t++;
                        g[i][j] = -1;
                    }
                }
                g[i][i] = t;
            }
            cout << calc() << endl;
        }
        return 0;
    }
    矩阵树
    int n,vis[505],used[505],pre[505],cost[505],a[505][505],maxd[505][505];
    //不连通返回-1,否则返回次小花费
    int prim()
    {
        int ans = 0;
        memset(vis,0,sizeof(vis));
        memset(used,0,sizeof(used));
        memset(maxd,0,sizeof(maxd));
        vis[1] = 1;
        for(int i = 2;i <= n;i++)   cost[i] = a[1][i];
        for(int i = 2;i <= n;i++)
        {
            int minn = INF;
            int k = -1;
            for(int j = 1;j <= n;j++)
            {
                if(!vis[j] && minn > cost[j])
                {
                    minn = cost[j];
                    k = j;
                }
            }
            if(minn == INF) return -1;
            ans += minn;
            vis[k] = 1;
            for(int j = 1;j <= n;j++)
            {
                if(vis[j])  maxd[j][k] = maxd[k][j] = max(maxd[j][pre[k]],cost[k]);
                if(!vis[j] && cost[j] > a[k][j])
                {
                    cost[j] = a[k][j];
                    pre[j] = k;
                }
            }
        }
        return ans;
    }
    次小生成树

    有向图的强联通分量个数:

    //O(n+m)
    //缩点,belong保存每个点属于的强联通集合编号
    int n,m,vis[10005],dfn[10005],low[10005],belong[10005],cnt,ans;
    vector<int> v[10005];
    
    void tarjan(int now)
    {
        stack<int> s;
        s.push(now);
        vis[now] = 1;
        dfn[now] = low[now] = ++cnt;
        for(int i = 0;i < v[now].size();i++)
        {
            int t = v[now][i];
            if(dfn[t] == 0)
            {
                tarjan(t);
                low[now] = min(low[now],low[t]);
            }
            else if(vis[t])    low[now] = min(low[now],dfn[t]);
        }
        if(dfn[now] == low[now])
        {
            ans++;
            while(!s.empty())
            {
                int t = s.top();
                s.pop();
                vis[t] = 0;
                belong[t] = ans;
                if(t == now)    break;
            }
        }
    }
    
    int main()
    {
        for(int i = 1;i <= n;i++)
        {
            if(dfn[i] == 0) tarjan(i);
        }
    }
    tarjan
    //O(n+m)
    #include<bits/stdc++.h>
    using namespace std;
    
    int n,m,vis1[10005],vis2[10005],ans;
    vector<int> v1[10005],v2[10005];
    stack<int> s;
    
    void dfs1(int now)
    {
        vis1[now] = 1;
        for(int i = 0;i < v1[now].size();i++)
        {
            int t = v1[now][i];
            if(vis1[t])  continue;
            dfs1(t);
        }
        s.push(now);
    }
    
    void dfs2(int now)
    {
        vis2[now] = 1;
        for(int i = 0;i < v2[now].size();i++)
        {
            int t = v2[now][i];
            if(vis2[t]) continue;
            dfs2(t);
        }
    }
    
    int main()
    {
        ios::sync_with_stdio(false);
        while(scanf("%d%d",&n,&m) &&(n+m))
        {
            for(int i = 1;i <= n;i++)
            {
                v1[i].clear();
                v2[i].clear();
            }
            memset(vis1,0,sizeof(vis1));
            memset(vis2,0,sizeof(vis2));
            while(!s.empty())   s.pop();
            ans = 0;
            while(m--)
            {
                int x,y;
                scanf("%d%d",&x,&y);
                v1[x].push_back(y);
                v2[y].push_back(x);
            }
            for(int i = 1;i <= n;i++)
            {
                if(!vis1[i]) dfs1(i);
            }
            while(!s.empty())
            {
                if(!vis2[s.top()])
                {
                    ans++;
                    dfs2(s.top());
                }
                s.pop();
            }
            if(ans == 1)  printf("Yes
    ");
            else    printf("No
    ");
        }
        return 0;
    }
    kosaraju

    无向图中一些基本概念:

    割点集合:删除这个顶点集合,以及这个集合中所有顶点关联的边以后,原图变成多个连通块。
    点连通度:最小割点集合中的顶点数。
    割边集合:删除这个边集合以后,原图变成多个连通块。
    边连通度:最小割边集合中的边数。

    点双连通(双连通或重连通):无向连通图的点连通度大于1。
    割点(关节点):当且仅当这个图的点连通度为1,则割点集合的唯一元素被称为割点。
    边双连通(双连通或重连通):无向连通图的边连通度大于1。
    桥(关节边 ):当且仅当这个图的边连通度为 1,则割边集合的唯一元素被称为桥。

    边双连通分支:在连通分支中去掉一条边,连通分支仍连通。
    点双连通分支(块):在连通分支中去掉一个点,连通分支仍连通。

    struct bridge
    {
        int u,int v;
        bridge(int a,int b):u(a),v(b){}
    };
    vector<bridge> ansb;
    vector<int> absc;
    
    //ansb保存桥,ansc保存割点
    void tarjan(int now,int pre)
    {
        low[now] = dfn[now] = ++cnt;
        int son = 0;
        for(int i = 0;i < v[now].size();i++)
        {
            int t = v[now][i];
            if(t == pre)    continue;
            if(!dfn[t])
            {
                son++;
                tarjan(t,now);
                low[now] = max(low[now],low[t]);
                //桥,(u,v)为树枝,low[v] > dfn[u]
                if(low[t] > dfn[now])
                {
                    ansb.push_back(bridge(now,t));
                    ansb.push_back(bridge(t,now));
                }
                //割点,(u,v)父子边,u不为树根,low[v] >= dfn[u]
                if(now != root && low[t] >= dfn[now]) ansc.push_back(t);
            }
            else    low[now] = max(low[now],low[t]);
        }
        //割点,u为根,分支数大于1
        if(now == root && son > 1)  ansc.push_back(now);
    }
    求割点和桥
    去掉桥,其余的连通分支就是边双连通分支了。
    一个有桥的连通图要变成双连通图的话,把双连通子图缩成一个点,形成一棵树。
    再加上(leaf+1)/2条边。
    求边双连通分支
    //cutcnt表示个数
    //block储存每个点连通分支
    stack<int> s;
    vector<int> block[10005];
    void tarjan(int now,int pre)
    {
        low[now] = dfn[now] = ++cnt;
        s.push(now);
        for(int i = 0;i < v[now].size();i++)
        {
            int t = v[now][i];
            if(t == pre)    continue;
            if(!dfn[t])
            {
                tarjan(t,now);
                low[now] = max(low[now],low[t]);
                if(low[t] >= dfn[now])
                {
                    cutcnt++;
                    block[cutcnt].clear();
                    while(!s.empty())
                    {
                        int tt = s.top();
                        s.pop();
                        block[cutcnt].push_back(tt);
                        if(tt = t)  break;
                    }
                    block[cutcnt].push_back(now);
                }
            }
            else    low[now] = max(low[now],low[t]);
        }
    }
    求点双连通分支

    struct xxx
    {
        int u,v,w;
    }e[10005];
    int n,m,a[55],sum[55],cnt,in[800],pre[800],vis[800],id[800];
    
    void addedge(int u,int v,int w)
    {
        e[cnt].u = u;
        e[cnt].v = v;
        e[cnt++].w = w;
    }
    
    
    //已处理重边,不存在最小树形图返回-1,否则返回最小值
    int zhuliu(int root, int n, int m)
    {
        int ans = 0;
        while(1)
        {
            //找最小入边
            for(int i = 0;i < n;i++)    in[i] = INF;
            for(int i = 0;  < m;i++)
            {
                int u = e[i].u;
                int v = e[i].v;
                if(e[i].w < in[v] && u != v)
                {
                    pre[v] = u;
                    in[v] = e[i].w;
                }     //去除自环和重边
            }
            for(int i = 0;i < n;i++)
            {
                if(i == root)   continue;
                if(in[i] == INF)    return -1;                                 //除了跟以外有点没有入边,则根无法到达它
            }
            int cnt = 0;                             //找环
            memset(id,-1,sizeof(id));
            memset(vis,-1,sizeof(vis));
            in[root] = 0;
            for(int i = 0;i < n;i++)
            {
                ans += in[i];
                int v = i;
                while(vis[v] != i && id[v] == -1 && v != root)  //每个点寻找其前序点,要么最终寻找至根部,要么找到一个环
                {
                    vis[v] = i;
                    v = pre[v];
                }
                if(v != root && id[v] == -1)//缩点
                {
                    for(int u = pre[v];u != v;u = pre[u])   id[u] = cnt;
                    id[v] = cnt++;
                }
            }
            if(cnt == 0)    break; //无环   则break
            for(int i = 0;i < n;i++)
            {
                if(id[i] == -1) id[i] = cnt++;
            }
            for(int i = 0;i < m;)
            {
                int u = e[i].u;
                int v = e[i].v;
                e[i].u = id[u];
                e[i].v = id[v];
                if(id[u] != id[v])  e[i++].w -= in[v];
                else    e[i]=e[--m];
            }
            n = cnt;
            root = id[root];
        }
        return ans;
    }
    最小树形图zhuliu

    二分图:

    最大匹配 == 最小点覆盖

    最小路径覆盖 == 最大独立集 == 顶点数-最大匹配

    最大团 == 补图最大独立集

    int n,m,l;
    int linker[505];  
    bool used[505];  
    int g[505][505];
    
    bool dfs(int u)
    {
        for(int v = 1;v <= m;v++)
        {
            if(g[u][v] && !used[v])
            {
                used[v] = 1;
                if(linker[v] == -1 || dfs(linker[v]))
                {
                    linker[v] = u;
                    return 1;
                }  
            }  
        }
        return 0;  
    }  
    
    int MaxMatch()
    {  
        int ans = 0;  
        memset(linker,-1,sizeof(linker));  
        for(int i = 1;i <= n;i++)
        {  
            memset(used,0,sizeof(used));
            if(dfs(i))    ans++;
        }
        return ans;
    }  
    匈牙利邻接矩阵
    //O(nl)
    int n,m,l;
    int linker[505];  
    bool used[505];  
    vector<int> v[505];
    
    bool dfs(int u)
    {
        for(int i = 0;i < v[u].size();i++)
        {
            int t = v[u][i];
            if(!used[t])
            {
                used[t] = 1;
                if(linker[t] == -1 || dfs(linker[t]))
                {
                    linker[t] = u;
                    return 1;
                }  
            }  
        }
        return 0;  
    }  
    
    int MaxMatch()
    {  
        int ans = 0;  
        memset(linker,-1,sizeof(linker));  
        for(int i = 1;i <= n;i++)
        {  
            memset(used,0,sizeof(used));
            if(dfs(i))    ans++;
        }
        return ans;
    }  
    匈牙利邻接表
    //O(V^0.5 E)
    //适用于数据较大的二分匹配 
    
    int g[MAXN][MAXN],Mx[MAXN],My[MAXN],Nx,Ny;
    int dx[MAXN],dy[MAXN],dis;
    bool vst[MAXN];
    bool searchP()
    {
        queue<int>Q;
        dis=INF;
        memset(dx,-1,sizeof(dx));
        memset(dy,-1,sizeof(dy));
        for(int i=0;i<Nx;i++)
            if(Mx[i]==-1)
            {
                Q.push(i);
                dx[i]=0;
            }  
        while(!Q.empty())
        {
            int u=Q.front();
            Q.pop();
            if(dx[u]>dis)  break;
            for(int v=0;v<Ny;v++)
                if(g[u][v]&&dy[v]==-1)
                {
                    dy[v]=dx[u]+1;
                    if(My[v]==-1)  dis=dy[v];
                    else
                    {
                        dx[My[v]]=dy[v]+1;
                        Q.push(My[v]);
                    }    
                }    
        }  
        return dis!=INF;    
    }    
    bool DFS(int u)
    {
        for(int v=0;v<Ny;v++)
           if(!vst[v]&&g[u][v]&&dy[v]==dx[u]+1)
           {
               vst[v]=1;
               if(My[v]!=-1&&dy[v]==dis) continue;
               if(My[v]==-1||DFS(My[v]))
               {
                   My[v]=u;
                   Mx[u]=v;
                   return 1;
               }    
           }  
        return 0;  
    }
    int MaxMatch()
    {
        int res=0;
        memset(Mx,-1,sizeof(Mx));
        memset(My,-1,sizeof(My));
        while(searchP())
        {
            memset(vst,0,sizeof(vst));
            for(int i=0;i<Nx;i++)
              if(Mx[i]==-1&&DFS(i))  res++;
        }
        return res;   
    }    
    Hopcroft-Carp
    bool dfs(int u)
    {
        for(int i = 0;i < v[u].size();i++)
        {
            int t = v[u][i];
            if(used[t]) continue;
            used[t] = 1;
            if(linker[t][0] < capacity[t])
            {
                linker[t][++linker[t][0]] = u;
                return 1;
            }
            for(int j = 1;j <= capacity[t];j++)
            {
                if(dfs(linker[t][j]))
                {
                    linker[t][j] = u;
                    return 1;
                }
            }
        }
            return 0;
    }
    
    int MaxMatch()
    {
        int ans = 0;
        memset(linker,0,sizeof(linker));
        for(int i = 1;i <= n;i++)
        {
            memset(used,0,sizeof(used));
            if(dfs(i))    ans++;
        }
        return ans;
    }
    多重匹配匈牙利
    int n,m,g[305][305],linker[305],lx[305],ly[305],slack[305],visx[305],visy[305];
    
    bool dfs(int u)
    {
        visx[u] = 1;
        for(int i = 1;i <= m;i++)
        {
            if(visy[i]) continue;
            int t = lx[u]+ly[i]-g[u][i];
            if(t == 0)
            {
                visy[i] = 1;
                if(!linker[i]|| dfs(linker[i]))
                {
                    linker[i] = u;
                    return 1;
                }
            }
            else    slack[i] = min(slack[i],t);
        }
        return 0;
    }
    
    int KM()
    {
        memset(linker,0,sizeof(linker));
        memset(ly,0,sizeof(ly));
        for(int i = 1;i <= n;i++)
        {
            lx[i] = -INF;
            for(int j = 1;j <= m;j++)
            {
                if(g[i][j] > lx[i])  lx[i] = g[i][j];
            }
        }
        for(int i = 1;i <= n;i++)
        {
            memset(slack,0x3f,sizeof(slack));
            while(1)
            {
                memset(visx,0,sizeof(visx));
                memset(visy,0,sizeof(visy));
                if(dfs(i))   break;
                int d = INF;
                for(int j = 1;j <= m;j++)
                {
                    if(!visy[j]) d = min(d,slack[j]);
                }
                for(int j = 1;j <= n;j++)
                {
                    if(visx[j])  lx[j] -= d;
                }
                for(int j = 1;j <= m;j++)
                {
                    if(visy[j])  ly[j] += d;
                    else slack[j] -= d;
                }
            }
        }
        int ans = 0;
        for(int i = 1;i <= m;i++)
        {
            if(linker[i])   ans += g[linker[i]][i];
        }
        return ans;
    }
    二分图最大权KM

    网络流:

    最大流 == 最小割

    //s为源点,t为汇点
    //O(nm^2)
    int n,m,s,t,a[20][20],pre[20],vis[20];
    
    bool bfs()
    {
        memset(pre,0,sizeof(pre));
        memset(vis,0,sizeof(vis));
        vis[s] = 1;
        queue<int> q;
        q.push(s);
        while(!q.empty())
        {
            int now = q.front();
            q.pop();
            if(now == t)    return 1;
            for(int i = 1;i <= n;i++)
            {
                if(vis[i])  continue;
                if(a[now][i])
                {
                    q.push(i);
                    pre[i] = now;
                    vis[i] = 1;
                }
            }
        }
        return 0;
    }
    
    int EdmondsKarp()
    {
       int ans = 0;
       while(bfs())
       {
           int minn = 1e9;
           for(int i = t;i != s;i = pre[i]) minn = min(minn,a[pre[i]][i]);
           for(int i = t;i != s;i = pre[i])
           {
               a[pre[i]][i] -= minn;
               a[i][pre[i]] += minn;
           }
           ans += minn;
       }
       return ans;
    }
    最大流EdmondsKarp
    struct edge
    {
        int u,v,c,next;
    }e[20*N];
    int n,m,sp,tp,cnt,head[N],d[N];
    //源点汇点全局定义
    
    void init()
    {
        cnt = 0;
        memset(head,-1,sizeof(head));
    }
    
    void addedge(int u,int v,int c)
    {
        e[cnt].u = u;e[cnt].v = v;e[cnt].c = c;
        e[cnt].next = head[u];head[u] = cnt++;
        e[cnt].u = v;e[cnt].v = u;e[cnt].c = 0;
        e[cnt].next = head[v];head[v] = cnt++;
    }
    
    int bfs()
    {
        queue<int> q;
        memset(d,-1,sizeof(d));
        d[sp]=0;
        q.push(sp);
        while(!q.empty())
        {
            int cur = q.front();
            q.pop();
            for(int i = head[cur];i != -1;i = e[i].next)
            {
                int u = e[i].v;
                if(d[u] == -1 && e[i].c > 0)
                {
                    d[u] = d[cur]+1;
                    q.push(u);
                }
            }
        }
        return d[tp] != -1;
    }
    
    int dfs(int a,int b)
    {
        int r = 0;
        if(a == tp) return b;
        for(int i = head[a];i != -1 && r < b;i = e[i].next)
        {
            int u = e[i].v;
            if(e[i].c > 0 && d[u] == d[a]+1)
            {
                int x = min(e[i].c,b-r);
                x = dfs(u,x);
                r += x;
                e[i].c -= x;
                e[i^1].c += x;
            }
        }
        if(!r)  d[a] =- 2;
        return r;
    }
    
    int dinic()
    {
        int ans = 0,t;
        while(bfs())
        {
            while(t = dfs(sp,INF))
            ans += t;
        }
        return ans;
    }
    dinic
    struct Edge
    {
        int to,next,cap,flow;
    } edge[M];
    int n,m,cnt,head[N],gap[N],d[N],cur[N],que[N],p[N];
    
    void init()
    {
        cnt = 0;
        memset(head,-1,sizeof(head));
    }
    
    void addedge(int u,int v,int c)
    {
        edge[cnt].to = v;
        edge[cnt].cap = c;
        edge[cnt].flow = 0;
        edge[cnt].next = head[u];
        head[u] = cnt++;
        edge[cnt].to = u;
        edge[cnt].cap = 0;
        edge[cnt].flow = 0;
        edge[cnt].next = head[v];
        head[v] = cnt++;
    }
    
    void bfs(int source,int sink)
    {
        memset(d,-1,sizeof(d));
        memset(gap,0,sizeof(gap));
        gap[0] = 1;
        int front = 0,rear = 0;
        d[sink] = 0;
        que[rear++] = sink;
        while(front != rear)
        {
            int u = que[front++];
            for(int i = head[u];i != -1;i = edge[i].next)
            {
                int v = edge[i].to;
                if(d[v] != -1) continue;
                que[rear++] = v;
                d[v] = d[u]+1;
                gap[d[v]]++;
            }
        }
    }
    
    int isap(int source,int sink,int N)        //源点,汇点,总点数
    {
        bfs(source,sink);
        memcpy(cur,head,sizeof(head));
        int top = 0,x = source,flow = 0;
        while(d[source] < N)
        {
            if(x == sink)
            {
                int Min = INF,inser;
                for(int i = 0;i < top;i++)
                {
                    if(Min > edge[p[i]].cap-edge[p[i]].flow)
                    {
                        Min = edge[p[i]].cap-edge[p[i]].flow;
                        inser = i;
                    }
                }
                for(int i = 0;i < top;i++)
                {
                    edge[p[i]].flow += Min;
                    edge[p[i]^1].flow -= Min;
                }
                flow += Min;
                top = inser;
                x = edge[p[top]^1].to;
                continue;
            }
            int ok = 0;
            for(int i = cur[x];i != -1;i = edge[i].next)
            {
                int v = edge[i].to;
                if(edge[i].cap > edge[i].flow && d[v]+1 == d[x])
                {
                    ok = 1;
                    cur[x] = i;
                    p[top++] = i;
                    x = edge[i].to;
                    break;
                }
            }
            if(!ok)
            {
                int Min = N;
                for(int i = head[x];i != -1;i = edge[i].next)
                {
                    if(edge[i].cap > edge[i].flow && d[edge[i].to] < Min)
                    {
                        Min = d[edge[i].to];
                        cur[x] = i;
                    }
                }
                if(--gap[d[x]] == 0) break;
                gap[d[x] = Min+1]++;
                if(x != source) x = edge[p[--top]^1].to;
            }
        }
        return flow;
    }
    isap
    int n,m,s,t,pre[1005],vis[1005],dis[1005],head[1005],cnt = 0;
    struct ee
    {
        int u,v,cap,cost,next;
    }e[2005];
    
    void add(int u,int v,int cap,int cost)
    {
        e[cnt].u = u;
        e[cnt].v = v;
        e[cnt].cap = cap;
        e[cnt].cost = cost;
        e[cnt].next = head[u];
        head[u] = cnt++;
        e[cnt].u = v;
        e[cnt].v = u;
        e[cnt].cap = 0;
        e[cnt].cost = -cost;
        e[cnt].next = head[v];
        head[v] = cnt++;
    }
    
    bool spfa()
    {
        memset(vis,0,sizeof(vis));
        memset(pre,-1,sizeof(pre));
        for(int i = s;i <= t;i++)   dis[i] = 1e9;
        vis[s] = 1;
        dis[s] = 0;
        queue<int> q;
        q.push(s);
        while(!q.empty())
        {
            int u = q.front();
            q.pop();
            vis[u] = 0;
            for(int i = head[u];i != -1;i = e[i].next)
            {
                int v = e[i].v;
                if(e[i].cap && dis[v] > dis[u]+e[i].cost)
                {
                    dis[v] = dis[u]+e[i].cost;
                    pre[v] = i;
                    if(vis[v])  continue;
                    q.push(v);
                    vis[v] = 1;
                }
            }
        }
        if(dis[t] == 1e9)   return 0;
        return 1;
    }
    int mcmf()
    {
        int flow = 0,ans = 0;
        while(spfa())
        {
            int minn = 1e9;
            for(int i = pre[t];i != -1;i = pre[e[i].u]) minn = min(e[i].cap,minn);
            for(int i = pre[t];i != -1;i = pre[e[i].u])
            {
                e[i].cap -= minn;
                e[i^1].cap += minn;
            }
            flow += minn;
            ans += dis[t]*minn;
        }
        return ans;
    }
    最小费用最大流

    2-sat:

    x == 1           : x' -> x    (x必取)

    x and y == 1 : x' -> x ,y' -> y  (两个数必须全为1)

    x and y == 0 : y -> x' ,x -> y'  (两个数至少有一个为0)

    x or y == 1    : x' -> y ,y' -> x     (两个数至少有一个为1)

    x or y == 0    : x -> x' ,y -> y'         (两个数全为0) 

    x xor y == 1  : x -> y' ,y -> x' ,y' -> x ,x '-> y (两个数不同)

    x xor y == 0  : x -> y ,x' -> y' ,y -> x ,y' -> x'  (两个数相同)

    //可得到最小字典序的解
    #include<bits/stdc++.h>
    using namespace std;
    
    int n,m,vis[16005];
    vector<int> v[16005];
    stack<int> s;
    
    bool dfs(int u)
    {
        if(vis[u^1])    return 0;
        if(vis[u])  return 1;
        vis[u] = 1;
        s.push(u);
        for(int i = 0;i < v[u].size();i++)
        {
            int t = v[u][i];
            if(!dfs(t)) return 0;
        }
        return 1;
    }
    
    bool twosat(int n)
    {
        memset(vis,0,sizeof(vis));
        for(int i = 0;i < n;i += 2)
        {
            if(vis[i] || vis[i^1])  continue;
            while(!s.empty())   s.pop();
            if(!dfs(i))
            {
                while(!s.empty())
                {
                    vis[s.top()] = 0;
                    s.pop();
                }
                if(!dfs(i^1))   return 0;
            }
        }
        return 1;
    }
    
    int main()
    {
        ios::sync_with_stdio(false);
        while(cin >> n >> m)
        {
            for(int i = 0;i < 2*n;i++)  v[i].clear();
            memset(vis,0,sizeof(vis));
            while(m--)
            {
                int a,b;
                cin >> a >> b;
                a--;
                b--;
                v[a].push_back(b^1);
                v[b].push_back(a^1);
            }
            if(twosat(2*n))
            {
                for(int i = 0;i < 2*n;i++)
                {
                    if(vis[i])  cout << i+1 << endl;
                }
            }
            else    cout << "NIE" << endl;
        }
        return 0;
    }
    染色法
    int n,m,vis[2*N],dfn[2*N],low[2*N],belong[2*N],pos[2*N],deg[2*N],ok[2*N],cnt,color;
    vector<int> v[2*N],v2[2*N],ans;
    stack<int> st;
    
    //求任意解
    void top(int n)
    {
        ans.clear();
        memset(ok,0,sizeof(ok));
        queue<int> q;
        for(int i = 1;i <= color;i++)
        {
            if(deg[i] == 0) q.push(i);
        }
        while(!q.empty())
        {
            int now = q.front();
            q.pop();
            if(ok[now] == 0)
            {
                ok[now] = 1;
                ok[pos[now]] = 2;
            }
            for(int i = 0;i < v2[now].size();i++)
            {
                int t = v2[now][i];
                if(--deg[t] == 0)   q.push(t);
            }
        }
        for(int i = 0;i < n;i++)
        {
            if(ok[belong[i]] == 1)  ans.push_back(i);
        }
    }
    
    void tarjan(int now)
    {
        st.push(now);
        vis[now] = 1;
        dfn[now] = low[now] = ++cnt;
        for(int i = 0;i < v[now].size();i++)
        {
            int t = v[now][i];
            if(dfn[t] == 0)
            {
                tarjan(t);
                low[now] = min(low[now],low[t]);
            }
            else if(vis[t])    low[now] = min(low[now],dfn[t]);
        }
        if(dfn[now] == low[now])
        {
            color++;
            while(!st.empty())
            {
                int t = st.top();
                st.pop();
                vis[t] = 0;
                belong[t] = color;
                if(t == now)    break;
            }
        }
    }
    
    bool solve(int n)
    {
        for(int i = 0;i < n;i++)
        {
            if(dfn[i] == 0) tarjan(i);
        }
        for(int i = 0;i < n;i += 2)
        {
            if(belong[i] == belong[i^1])    return 0;
            pos[belong[i]] = belong[i^1];
            pos[belong[i^1]] = belong[i];
        }
        for(int i = 0;i < n;i++)
        {
            for(int j = 0;j < v[i].size();j++)
            {
                int t = v[i][j];
                if(belong[i] != belong[t])
                {
                    deg[belong[i]]++;
                    v2[belong[t]].push_back(belong[i]);
                }
            }
        }
        top(n);
        return 1;
    }
    tarjan缩点+拓扑排序

    struct point
    {
        int x,y,id;
        friend bool operator <(point a,point b)
        {
            if(a.x != b.x)  return a.x < b.x;
            return a.y < b.y;
        }
    }p[10005];
    struct Bit
    {
        int minn,pos;
        void init()
        {
            minn = INF;
            pos = -1;
        }
    }bit[10005];
    struct edge
    {
        int u,v,d;
        friend bool operator<(edge a,edge b)
        {
            return a.d < b.d;
        }
    }e[40005];
    int n,k,cnt,pre[10005],a[10005],b[10005];
    
    int findd(int x)
    {
        return pre[x] == x?x:findd(pre[x]);
    }
    
    void addedge(int u,int v,int d)
    {
        e[++cnt].u = u;
        e[cnt].v = v;
        e[cnt].d = d;
    }
    
    int lowbit(int x)
    {
        return x&-x;
    }
    
    void update(int i,int x,int pos)
    {
        while(i > 0)
        {
            if(x < bit[i].minn)
            {
                bit[i].minn = x;
                bit[i].pos = pos;
            }
            i -= lowbit(i);
        }
    }
    
    int ask(int i,int m)
    {
        int minn = INF,pos = -1;
        while(i <= m)
        {
            if(bit[i].minn < minn)
            {
                minn = bit[i].minn;
                pos = bit[i].pos;
            }
            i += lowbit(i);
        }
        return pos;
    }
    
    int dist(point a,point b)
    {
        return abs(a.x-b.x)+abs(a.y-b.y);
    }
    
    void manhattan()
    {
        cnt = 0;
        for(int dir = 0;dir < 4;dir++)
        {
            if(dir == 1 || dir == 3)
            {
                for(int i = 1;i <= n;i++)   swap(p[i].x,p[i].y);
            }
            else if(dir == 2)
            {
                for(int i = 1;i <= n;i++)   p[i].x = -p[i].x;
            }
            sort(p+1,p+1+n);
            for(int i = 1;i <= n;i++)   a[i] = b[i] = p[i].y-p[i].x;
            sort(b+1,b+1+n);
            int t = unique(b+1,b+n+1)-b-1;
            for(int i = 1;i <= t;i++)   bit[i].init();
            for(int i = n;i >= 1;i--)
            {
                int pos = lower_bound(b+1,b+1+t,a[i])-b+1;
                int ans = ask(pos,t);
                if(ans != -1)   addedge(p[i].id,p[ans].id,dist(p[i],p[ans]));
                update(pos,p[i].x+p[i].y,i);
            }
        }
    }
    
    //返回第k小的边长
    int solve(int k)
    {
        manhattan();
        for(int i = 1;i <= n;i++)   pre[i] = i;
        sort(e+1,e+1+cnt);
        for(int i = 1;i <= cnt;i++)
        {
            int u = e[i].u,v = e[i].v;
            int x = findd(u),y = findd(v);
            if(x != y)
            {
                pre[x] = y;
                if(--k == 0)    return e[i].d;
            }
        }
    }
    曼哈顿最小生成树

    //g[i][j]存放关系图:i,j是否有边,match[i]存放i所匹配的点
    //建图开始初始化g
    //最终匹配方案为match
    //复杂度O(n^3)
    //点是从1到n的
    bool g[MAXN][MAXN],inque[MAXN],inblossom[MAXN],inpath[MAXN];
    int match[MAXN],pre[MAXN],base[MAXN];
    queue<int> q;
    //找公共祖先
    int findancestor(int u,int v)
    {
        memset(inpath,false,sizeof(inpath));
        while(1)
        {
            u = base[u];
            inpath[u] = 1;
            if(match[u] == -1)  break;
            u = pre[match[u]];
        }
        while(1)
        {
            v = base[v];
            if(inpath[v])   return v;
            v = pre[match[v]];
        }
    }
    
    //压缩花
    void reset(int u,int anc)
    {
        while(u != anc)
        {
            int v = match[u];
            inblossom[base[u]] = 1;
            inblossom[base[v]] = 1;
            v = pre[v];
            if(base[v] != anc)  pre[v] = match[u];
            u = v;
        }
    }
    
    void contract(int u,int v,int n)
    {
        int anc = findancestor(u,v);
        memset(inblossom,0,sizeof(inblossom));
        reset(u,anc);
        reset(v,anc);
        if(base[u] != anc)  pre[u] = v;
        if(base[v] != anc)  pre[v] = u;
        for(int i = 1;i <= n;i++)
        {
            if(inblossom[base[i]])
            {
                base[i] = anc;
                if(!inque[i])
                {
                    q.push_back(i);
                    inque[i] = 1;
                }
            }
        }
    
    }
    
    bool bfs(int S,int n)
    {
        for(int i = 0;i <= n;i++)   pre[i]=-1,inque[i]=0,base[i]=i;
        q.clear();
        q.push_back(S);
        inque[S] = 1;
        while(!q.empty())
        {
            int u = q.front();
            q.pop();
            for(int v = 1;v <= n;v++)
            {
                if(g[u][v] && base[v] != base[u] && match[u] != v)
                {
                    if(v == S || match[v] !=-1 && pre[match[v]] != -1)  contract(u,v,n);
                    else if(pre[v] == -1)
                    {
                        pre[v] = u;
                        if(match[v] != -1)
                        {
                            q.push_back(match[v]);
                            inque[match[v]] = 1;
                        }
                        else
                        {
                            u = v;
                            while(u! = -1)
                            {
                                v = pre[u];
                                int w = match[v];
                                match[u] = v;
                                match[v] = u;
                                u = w;
                            }
                            return 1;
                        }
                    }
                }
            }
        }
        return 0;
    }
    
    int solve(int n)
    {
        memset(match,-1,sizeof(match));
        int ans = 0;
        for(int i=1;i<=n;i++)
        {
            if(match[i] == -1 && dfs(i,n))  ans++;
        }
        return ans;
    }
    一般图匹配带花树

    void dfs(int now,int pre)
    {
        dep[now] = dep[pre]+1;
        for(int i = 0;i < v[now].size();i++)
        {
            int t = v[now][i];
            if(t == pre)    continue;
            fa[t][0] = now;
            dfs(t,now);
        }
    }
    
    int lca(int x,int y)
    {
        if(dep[x] < dep[y]) swap(x,y);
        int t = dep[x]-dep[y];
        for(int i = 0;i <= 20;i++)
        {
            if((1<<i)&t)    x = fa[x][i];
        }
        if(x == y)  return x;
        for(int i = 20;i >= 0;i--)
        {
            if(fa[x][i] != fa[y][i])
            {
                x = fa[x][i];
                y = fa[y][i];
            }
        }
        return fa[x][0];
    }
    
    
    int main()
    {
        dfs(1,0);
        for(int i = 1;i <= 20;i++)
        {
            for(int j = 1;j <= n;j++)
            {
                fa[j][i] = fa[fa[j][i-1]][i-1];
            }
        }
    }
    最近公共祖先倍增lca
    int n,m,f[N*2],rmq[N*2];
    vector<int> v[N];
    
    struct ST
    {
        int mm[2*N],dp[2*N][20];
        void init(int n)
        {
            mm[0] = -1;
            for(int i = 1;i <= n;i++)
            {
                mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1];
                dp[i][0] = i;
            }
            for(int j = 1;j <= mm[n];j++)
            {
                for(int i = 1;i+(1<<j)-1 <= n;i++)  dp[i][j] = rmq[dp[i][j-1]] < rmq[dp[i+(1<<(j-1))][j-1]]?dp[i][j-1]:dp[i+(1<<(j-1))][j-1];
            }
        }
        int query(int a,int b)
        {
            if(a > b)   swap(a,b);
            int k = mm[b-a+1];
            return rmq[dp[a][k]] <= rmq[dp[b-(1<<k)+1][k]]?dp[a][k]:dp[b-(1<<k)+1][k];
        }
    }st;
    
    void dfs(int now,int pre,int dep)
    {
        f[++cnt] = now;
        rmq[cnt] = dep;
        p[now] = cnt;
        for(int i = 0;i < v[now].size();i++)
        {
            int t = v[now][i];
            if(t == pre)    continue;
            dfs(t,now,dep+1);
            f[++cnt] = now;
            rmq[cnt] = dep;
        }
    }
    
    void initlca(int root,int n)
    {
        cnt = 0;
        dfs(root,root,0);
        st.init(2*n-1);
    }
    
    int querylca(int x,int y)
    {
        return f[st.query(p[x],p[y])];
    }
    lca+rmq

    欧拉路径:

    ①无向图:连通,每个顶点度数都为偶数或者仅有两个点的度数为奇数。

    ②有向图:底图连通,所有顶点的出度 == 入度 或者 有且仅有一个顶点 出度 == 入度+1,有且仅有一个顶点 入度 == 出度+1。

    ③混合图:底图连通,存在欧拉回路,则一定存在欧拉路径。否则如果有且仅有两个点的(出度-入度)是奇数,那么给这两个点加边,判断是否存在欧拉回路。

    欧拉回路:

    ①无向图:连通,每个顶点度数都为偶数。

    ②有向图:底图连通,每个顶点出度等于入度。

    ③混合图:底图连通,网络流判断。

    vector<int> ans;
    
    struct edge
    {
        int to,next,id,dir,flag;
    }e[20005];
    
    void addedge(int u,int v,int id)
    {
        e[cnt].to = v;
        e[cnt].id = id;
        e[cnt].dir = 0;
        e[cnt].flag = 0;
        e[cnt].next = head[u];
        head[u] = cnt++;
        e[cnt].to = u;
        e[cnt].id = id;
        e[cnt].dir = 1;
        e[cnt].flag = 0;
        e[cnt].next = head[v];
        head[v] = cnt++;
    }
    
    vector<edge> ans;
    void dfs(int u)
    {
        for(int i = head[u];i != -1;i = e[i].next)
        {
            if(!e[i].flag)
            {
                e[i].flag = 1;
                e[i^1].flag = 0;
                dfs(e[i].to);
                ans.push_back(i);
            }
        }
    }
    无向图欧拉路径
    #define MAXN 250
    
    vector<int> ans;
    
    struct edge
    {
        int to,next,id,flag;
    }e[20005];
    
    void addedge(int u,int v,int id)
    {
        e[cnt].to = v;
        e[cnt].id = id;
        e[cnt].flag = 0;
        e[cnt].next = head[u];
        head[u] = cnt++;
    }
    
    vector<edge> ans;
    void dfs(int u)
    {
        for(int i = head[u];i != -1;i = e[i].next)
        {
            if(!e[i].flag)
            {
                e[i].flag = 1;
                dfs(e[i].to);
                ans.push_back(i);
            }
        }
    }
    有向图欧拉路径
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    #define INF 0x3f3f3f3f
    #define N 205
    using namespace std;
    
    struct edge
    {
        int u,v,cap,next;
    }e[20005];
    int n,m,cnt,head[N],dep[N],gap[N],cur[N],st[N],que[N],ind[N],outd[N];
    
    void addedge(int u,int v,int cap)
    {
        e[cnt].u = u;
        e[cnt].v = v;
        e[cnt].cap = cap;
        e[cnt].next = head[u];
        head[u] = cnt++;
        e[cnt].u = v;
        e[cnt].v = u;
        e[cnt].cap = 0;
        e[cnt].next = head[v];
        head[v] = cnt++;
    }
    
    void bfs(int des)
    {
        memset(dep,-1,sizeof(dep));
        memset(gap,0,sizeof(gap));
        gap[0] = 1;
        int front = 0, rear = 0;
        dep[des] = 0;
        que[rear++] = des;
        int u,v;
        while(front != rear)
        {
            u = que[front++];
            front %= N;
            for(int i = head[u];i != -1;i = e[i].next)
            {
                v = e[i].v;
                if(e[i].cap != 0 || dep[v] != -1)   continue;
                que[rear++] = v;
                rear %= N;
                ++gap[dep[v] = dep[u]+1];
            }
        }
    }
    
    int isap(int src,int des,int n)//源点、汇点、图中点的总数
    {
        bfs(des);
        int ans = 0,top = 0;
        memcpy(cur,head,sizeof(head));
        int u = src,i;
        while(dep[src] < n)
        {
            if(u == des)
            {
                int temp = INF,inser = n;
                for(i = 0;i != top;i++)
                {
                    if (temp > e[st[i]].cap)
                    {
                        temp = e[st[i]].cap;
                        inser = i;
                    }
                }
                for(i = 0;i != top;i++)
                {
                    e[st[i]].cap -= temp;
                    e[st[i]^1].cap += temp;
                }
                ans += temp;
                top = inser;
                u = e[st[top]].u;
            }
            if(u != des && !gap[dep[u]-1])  break;
            for(i = cur[u];i != -1;i = e[i].next)
            {
                if(e[i].cap != 0 && dep[u] == dep[e[i].v]+1)  break;
            }
            if(i != -1)
            {
                cur[u] = i;
                st[top++] = i;
                u = e[i].v;
            }
            else
            {
                int minn = n;
                for(i = head[u];i != -1;i = e[i].next)
                {
                    if(!e[i].cap)    continue;
                    if(minn > dep[e[i].v])
                    {
                        minn = dep[e[i].v];
                        cur[u] = i;
                    }
                }
                --gap[dep[u]];
                ++gap[dep[u] = minn+1];
                if(u != src)    u = e[st[--top]].u;
            }
        }
        return ans;
    }
    
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d",&n,&m);
            cnt = 0;
            memset(head,-1,sizeof(head));
            memset(ind,0,sizeof(ind));
            memset(outd,0,sizeof(outd));
            while(m--)
            {
                int x,y,z;
                scanf("%d%d%d",&x,&y,&z);
                outd[x]++;
                ind[y]++;
                if(z == 0)  addedge(x,y,1);
            }
            int sum = 0,flag = 1;
            for(int i = 1;i <= n;i++)
            {
                if(outd[i]-ind[i] > 0)
                {
                    addedge(0,i,(outd[i]-ind[i])/2);
                    sum += (outd[i]-ind[i])/2;
                }
                else    if(ind[i]-outd[i] > 0)  addedge(i,n+1,(ind[i]-outd[i])/2);
                if((outd[i]-ind[i])%2)  flag = 0;
            }
            if(flag && isap(0,n+1,n+2) == sum)    printf("possible
    ");
            else    printf("impossible
    ");
        }
        return 0;
    }
    混合图欧拉回路判断

  • 相关阅读:
    B0BO TFS 安装指南(转载)
    Web前端开发神器--WebStorm(JavaScript 开发工具) 8.0.3 中文汉化破解版
    huhamhire-hosts — Hosts文件自动配置工具
    JFinal tomcat配置根路径(包括windows和linux)
    JSON 之FastJson解析
    JFinal使用笔记1-部署demo项目到本地tomcat
    HDU 4891 The Great Pan
    FragmentActivity+FragmentTabHost+Fragement替代TabActibvity+TabHost+Activity
    HIT 2255 Not Fibonacci(矩阵高速幂)
    STM32学习之路-感觉自己走到了一个天大的坑里了!
  • 原文地址:https://www.cnblogs.com/zhurb/p/7341261.html
Copyright © 2020-2023  润新知