Codeforces 949C Data Center Maintenance

32 篇文章 0 订阅
9 篇文章 0 订阅

题目链接:http://codeforces.com/contest/949/problem/C

题意:一天有h小时,某公司有N个信息,每个信息给出一个时间,0-h-1, 现在有m个客户,每个客户有2个信息in1,in2,in1!=in2,问选择一个最小的信息集合,将这集合里的信息时间全部往后推一个小时,如果信息时间为h-1,则变成0。求这个最小集合,并且时间改变后,客户2个信息的时间t[in1[i]]!= t[in2[i]]。

题解:若当前客户信息1时间+1可以到达信息2时间,对信息1连一条到信息2的单向边,说明如果改1,2也要改,对M个客户做这个操作。然后缩点,要改变的集合肯定是某个缩过点,且出度为0的集合,统计下出度为0的集合,取size(S)最小的即可。

难点:题意过于复杂。

#include <bits/stdc++.h>

using namespace std;
using ll = long long ;
using ld = long double;

#define pb push_back
#define SZ(X) ((int)X.size())
#define mp make_pair
#define Fi first
#define Se second
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pli pair<ll,int>
#define pil pair<int,ll>
#define ALL(X) X.begin(),X.end()
#define RALL(X) X.rbegin(),X.rend()
#define rep(i,j,k) for(int i = j;i <= k;i ++)
#define per(i,j,k) for(int i = j;i >= k;i --)
#define mem(a,p) memset(a,p,sizeof(a))


const int N = 1E5 + 7;

vector<int>G[N];

int sta[N];
int instack[N];
int bcnt, belong[N];
int index, sz;
int dfn[N], low[N];

int in1[N],in2[N];
int t[N];

int out[N];

void tarjan(int u)
{
    instack[u] = true;
    dfn[u] = low[u] = ++index;
    sta[++sz] = u;
    for(auto v:G[u]) {
        if(!dfn[v]) {
            tarjan(v);
            low[u] = min(low[u], low[v]);
        } else if(instack[v]) {
            low[u] = min(low[u], dfn[v]);
        }
    }
    if(dfn[u] == low[u]) {
        int v;
        bcnt ++;
        do {
            v = sta[sz--];
            belong[v] = bcnt;
            instack[v] = false;
        }while(u != v);
    }
}

int S[N];
int main()
{
    int n, m, h;
    scanf("%d %d %d",&n, &m, &h);
    rep(i,1,n) scanf("%d",&t[i]);
    rep(i,1,m) scanf("%d %d",&in1[i],&in2[i]);
    rep(i,1,m) if(t[in1[i]]>t[in2[i]]) swap(in1[i],in2[i]);
    rep (i,1,m) {
        if(t[in1[i]]+1 == t[in2[i]]) G[in1[i]].pb(in2[i]);
        if((t[in2[i]]+1)%h == t[in1[i]]) G[in2[i]].pb(in1[i]);
    }
    rep(i,1,n) if(!dfn[i]) tarjan(i);
//    printf("%d\n",bcnt);
//    rep(i,1,n) printf("%d ",belong[i]);
    rep (i, 1, n) {
        for(auto u : G[i]) {
            if(belong[u] != belong[i]) out[belong[i]] ++;
        }
    }
    rep (i, 1, n) {
        S[belong[i]] ++;
    }
    int res = 1<<29;
    int p = -1;
    rep (i, 1, n) {
        if(out[belong[i]] == 0) {
            if(p == -1) res = S[belong[i]], p = belong[i];
            else {
                if(S[belong[i]] < res) {
                    p = belong[i];
                    res = S[belong[i]];
                }
            }
        }
    }
    printf("%d\n",res);
    rep (i, 1, n) {
        if(belong[i] == p) printf("%d ",i);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值