码迷,mamicode.com
首页 > 其他好文 > 详细

Codeforces 950E Data Center Maintenance ( 思维 && 强连通分量缩点 )

时间:2018-04-28 20:58:04      阅读:163      评论:0      收藏:0      [点我收藏+]

标签:splay   统计   scanf   style   one   mil   图片   alt   dde   

题意 : 给出 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\n", MM);
    for(int i=1; i<=N; i++)
        if(color[i] == which)
            printf("%d ", i);
    puts("");
    return 0;
}
View Code

 

Codeforces 950E Data Center Maintenance ( 思维 && 强连通分量缩点 )

标签:splay   统计   scanf   style   one   mil   图片   alt   dde   

原文地址:https://www.cnblogs.com/Rubbishes/p/8969196.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!