zoukankan      html  css  js  c++  java
  • cf949C 建模,SCC缩点

    /*
    给定n个数据中心,m份资料,每份资料在其中的两个中心备份,一天可供下载的时间是h小时
    中心i在第hi小时需要维护,无法下载
    现在要将一些中心的维护时间往后推1小时,使得任意时刻每份资料都可以被下载,请问最少选择多少个数据中心,
    
    某个中心维护时,在其中资料无法下载,必须到其他点下载,
    如果该点对应的点也在维护,那么这个对应点的维护必须往后推
    对应点往后推时继续和其余点矛盾,那么其余点也要往后
    
    所以,如果同一份数据的两个点相隔一小时,那么这两个点要么不推迟,要推迟就要一起推迟, 
    
    建立模型:点x和点y有相同的资料,并且hx+1==hy,那么加有向边(x,y)
    最后得到的图中,一个强连通分量内的所有点必须一起选择
    缩点构成DAG,选择出度为0的点即可 
    */
    #include<bits/stdc++.h>
    using namespace std;
    #define maxn 100005
    struct Edge{int to,nxt;}edge[maxn<<2];
    int n,m,t,h[maxn],head[maxn],tot,d[maxn][2];
    
    int c[maxn],low[maxn],dfn[maxn],stk[maxn],ins[maxn],ind,top;
    int cnt;
    vector<int>scc[maxn];
    void tarjan(int x){
        dfn[x]=low[x]=++ind;
        stk[++top]=x;ins[x]=1;
        for(int i=head[x];i!=-1;i=edge[i].nxt){
            int y=edge[i].to;
            if(!dfn[y]){//树枝边
                tarjan(y); 
                low[x]=min(low[x],low[y]);
            }
            else if(ins[y])//后向边 
                low[x]=min(low[x],dfn[y]);
        }
        if(dfn[x]==low[x]){
            cnt++;
            int y;
            do{
                y=stk[top--];
                ins[y]=0;
                c[y]=cnt;scc[cnt].push_back(y);
            }while(x!=y);
        }
    }
    
    void init(){
        tot=0;
        memset(head,-1,sizeof head);
    }
    void addedge(int u,int v){
        edge[tot].nxt=head[u];
        edge[tot].to=v;
        head[u]=tot++;
    }
    int in[maxn],out[maxn];
    int main(){
        init();
        cin>>n>>m>>t;
        for(int i=1;i<=n;i++)scanf("%d",&h[i]);
        for(int i=1;i<=m;i++)scanf("%d%d",&d[i][0],&d[i][1]);
        for(int i=1;i<=m;i++){//建图 
            if((h[d[i][0]]+1)%t==h[d[i][1]])
                addedge(d[i][0],d[i][1]);
            if((h[d[i][1]]+1)%t==h[d[i][0]])
                addedge(d[i][1],d[i][0]);
        }
        for(int i=1;i<=n;i++)
            if(!dfn[i])
                tarjan(i); 
        for(int x=1;x<=n;x++)
            for(int i=head[x];i!=-1;i=edge[i].nxt){
                int y=edge[i].to;
                if(c[x]==c[y])continue;
                in[c[y]]++;out[c[x]]++;
            }
        int ans=0x3f3f3f3f,k;
        for(int i=1;i<=cnt;i++)
            if(out[i]==0 && scc[i].size()<ans)
                k=i,ans=scc[i].size();
        cout<<ans<<endl;
        for(int i=0;i<scc[k].size();i++)
            printf("%d ",scc[k][i]);
    } 
  • 相关阅读:
    PHP自动加载(__autoload和spl_autoload_register)
    抽象工厂模式
    工厂方法模式
    简单工厂模式
    组合
    二叉树的层次遍历 II
    umask命令
    二叉树的所有路径
    CDN缓存的理解
    Js中RegExp对象
  • 原文地址:https://www.cnblogs.com/zsben991126/p/10464493.html
Copyright © 2011-2022 走看看