zoukankan      html  css  js  c++  java
  • Codeforces 950E Data Center Maintenance ( 思维 && 强连通分量缩点 )

    题意 : 给出 n 个点,每个点有一个维护时间 a[i]。m 个条件,每个条件有2个点(x,y)且 a[x] != a[y]。选择最少的 k (最少一个)个点,使其值加1后,m个条件仍成立。

    分析 : 

    发现改变某些数加一后可能产生联动效应

    换句话说就是改变某些数则必须改变另一些数来维持 m 个条件的成立

    这个可以用图来表示,对于给出来的每一个 (x, y) 如果改变 x 后等于 y 则连 x => y 边

    表示要改变 x 则必须改变 y,然后对于 y 进行同样的判断是否连边

    最后建完图后,若有成环的,则这个环上的点要加一改变,则环上所有点都必须进行改变

    因此将整个图进行强连通分量缩点,最后考察所有出度为 0 的的分量,哪个分量点最少

    则这个点集就是答案,出度不为 0 的点肯定不是最优的,因为这些点定会回到出度为 0 的点

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 1e5 + 10;
    const int maxm = 2e5 + 10;
    struct EDGE{ int v, nxt; }Edge[maxm];
    int Head[maxn], cnt;
    int DFN[maxn], LOW[maxn], color[maxn], INDEX, id;
    bool vis[maxn], out[maxn];
    stack<int> stk;
    vector<int> num[maxn];
    int N, M, H;
    
    inline void init()
    {
        while(!stk.empty()) stk.pop();
        for(int i=0; i<=N; i++){
            Head[i] = DFN[i] = LOW[i] = color[i] = -1;
            out[i] = false;
           num[i].clear();
        }cnt = INDEX = id = 0;
    }
    
    inline void AddEdge(int from, int to)
    {
        Edge[cnt].v = to;
        Edge[cnt].nxt = Head[from];
        Head[from] = cnt++;
    }
    
    inline void tarjan(int u)
    {
        DFN[u] = LOW[u] = INDEX++;
        stk.push(u);
        vis[u] = true;
        for(int i=Head[u]; i!=-1; i=Edge[i].nxt){
            int Eiv = Edge[i].v;
            if(DFN[Eiv] == -1){
                tarjan(Eiv);
                LOW[u] = min(LOW[u], LOW[Eiv]);
            }else{
                if(vis[Eiv])
                    LOW[u] = min(LOW[u], LOW[Eiv]);
            }
        }
    
        if(DFN[u] == LOW[u]){
            color[u] = ++id;
            num[id].push_back(u);;
            vis[u] = false;
            while(stk.top() != u){
                vis[stk.top()] = false;
                color[stk.top()] = id;
                num[id].push_back(stk.top());
                stk.pop();
            }
            stk.pop();
        }
    }
    
    int arr[maxn];
    int main(void)
    {
        scanf("%d %d %d", &N, &M, &H);
    
        init();
    
        for(int i=1; i<=N; i++)
            scanf("%d", &arr[i]);
    
        int u, v;
        while(M--){
            scanf("%d %d", &u, &v);
            if((arr[u]+1)%H == arr[v]) AddEdge(u, v);
            if((arr[v]+1)%H == arr[u]) AddEdge(v, u);
        }
    
        for(int i=1; i<=N; i++)
            if(DFN[i] == -1)
                tarjan(i);///强连通分量缩点
    
        for(int i=1; i<=id; i++){///统计缩点后每个点的出入度情况
            for(int j=0; j<num[i].size(); j++){
                u = num[i][j];
                for(int k=Head[u]; k!=-1; k=Edge[k].nxt){
                    int Eiv = Edge[k].v;
                    if(color[Eiv] != i){
                        out[i] = true;
                        break;
                    }
                }
                if(out[i]) break;
            }
        }
    
        int MM = 0x3f3f3f3f, which;
        for(int i=1; i<=id; i++){
            if(!out[i] && num[i].size() < MM){
                MM = num[i].size();
                which = i;
            }
        }
    
        printf("%d
    ", MM);
        for(int i=1; i<=N; i++)
            if(color[i] == which)
                printf("%d ", i);
        puts("");
        return 0;
    }
    View Code
  • 相关阅读:
    总结一下矩阵的基本操作
    洛谷|P4281 [AHOI2008]紧急集合 / 聚会
    CQYZ OJ|Contest 133|祖孙询问
    博客主题分享
    USACO1.1|黑色星期五Friday the Thirteenth
    USACO1.1.2|贪婪的送礼者
    POJ1664|DFS水题
    树状数组的区间查询与区间修改
    N0lP2018爆零记录
    A了一道dijkstra板子
  • 原文地址:https://www.cnblogs.com/qwertiLH/p/8969196.html
Copyright © 2011-2022 走看看