zoukankan      html  css  js  c++  java
  • POJ

    题意:给出一个有向图
    输出1:至少要向多少台电脑放文件能使所有电脑都能得到文件
    输出2:至少加多少条边,可以使得在任意地方放文件,文件都能到达任意一台电脑
    思路:从题意上来看就是 寻找有向图中的强连通分量(极大强连通子图)
    输出2即是:在DAG上要加几条边,才能使得DAG变成强连通图
    所以使用tarjan算法,我们就把强连通分量缩成一个点,然后再根据这些点的出入度来增加边
    假设n个入度为0的点,m个出度为0的点
    (1)若m<=n 加了n边后 连接入度和出度为0的点
    (2)若m >n,则还有m-n个入度为0的点没有解决,所以还要加上m-n边
    即加边为max(m,n); 如果只有一个强连通分量时就不需要加边了

    完整代码:(详细注解)

    #include <cstdio>
    #include <stack>
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int maxn = 1e3;
    const int maxm = 1e5;
    struct Edge{
        int v,next;
        int u;
    }edge[maxm];
    int head[maxn];
    int top,num;
    int dfn[maxn],low[maxn],belong[maxn];//belong相当于染色,把同一个连通图标记为一种颜色
    int in[maxn],out[maxn];//出入度
    int instack[maxn];//标记是否在栈中
    int index;
    stack<int>Stack;
    void tarjan(int x){
        //(1)结点u初值
        low[x] = dfn[x] = ++index;
        instack[x] = 1;
        //(2)压入栈中
        Stack.push(x);
        //(3)枚举每一条边
        for(int i = head[x]; ~i;i= edge[i].next){
         //(4)入过结点u为强连通分量的根节点时
            int v = edge[i].v;
            //(5)没有被访问时候递归搜索,搜到底了之后就并到父节点
            if(!dfn[v]){
                tarjan(v);
                low[x] = min(low[x],low[v]);
            }
            //(5*)如果结点已在栈中就并其时间戳:因为在栈中意味着先就被访问过,也就是该结点的祖先结点
            else if(instack[v]){
             low[x]
    = min(low[x],low[v]); } } //(6)找到根部分 if(low[x] == dfn[x]){ int t; ++num;//强连通分量个数 do{ t = Stack.top(); belong[t] = num; //出栈 instack[t] = 0; Stack.pop(); }while(t != x);//直到退出结点位置到其本身 } } void add(int u,int v){ edge[top].v = v; edge[top].next = head[u]; head[u] = top++; } void init(){ memset(head,-1,sizeof(head)); memset(instack,0,sizeof(instack)); memset(in,0,sizeof(in)); memset(out,0,sizeof(out)); // memset(dfn,0,sizeof(dfn)); // memset(low,0,sizeof(low)); // memset(belong,0,sizeof(belong)); } int main(){ init(); int n,x; cin>>n; for(int i = 1;i<=n;i++){ while(cin>>x&&x) add(i,x); } for(int i = 1;i<=n;i++){ //没有被访问就进行tarjan if(!dfn[i]) tarjan(i); } if(num == 1) { cout<<1<<endl<<0<<endl; return 0; } for(int i = 1;i<=n ; i++){ for(int j = head[i]; ~j ; j = edge[j].next){ int v = edge[j].v; //如果不在一个分量中(即缩点之后的结点关系) if(belong[i] != belong[v]){ out[belong[i]]++; in[belong[v]]++; } } } int sum1,sum2; sum1 = sum2 = 0; for(int i = 1; i <= num;i++){ if(!out[i]) sum1++; if(!in[i]) sum2++; } cout<<sum2<<endl<<max(sum1,sum2)<<endl; return 0; }
  • 相关阅读:
    代码仓库创建规范
    在阿里云托管的k8s上使用nas做动态存储
    YApi——手摸手,带你在Win10环境下安装YApi可视化接口管理平台
    SwiftUI
    Istio多集群(1)-多控制面
    使用kind搭建kubernetes
    Envoy 代理中的请求的生命周期
    Istio中的流量配置
    Istio 的配置分析
    istio部署模型
  • 原文地址:https://www.cnblogs.com/Tianwell/p/11313731.html
Copyright © 2011-2022 走看看