• 暑假考试题2:聚会party(类拓扑+tarjan)


    题目:

    分析:

    如果没有:每个被邀请的人都直接认识另外至少d个被邀请的人 这个限制的话,就直接跑tarjan求最大的连通块。

    加了这个限制之后,明显有些点是不符合的,我们可以考虑删掉这些点后再跑tarjan。

    一个点的入度小于d,就是不满足的,就将与其相连的边都删掉。但这样又会导致与其相连的点因为与它这条边被删去而同样不满足条件,又需要删去。

    于是就可以用一个队列保存需要被删的点,是不是很熟悉,没错,就很像拓扑,只是拓扑只将入度为0的入队,而这里将入度小于d的入队

    #include<bits/stdc++.h>
    using namespace std;
    #define N 200005
    int cnt=0,vis[N],T=0,bel[N],low[N],stk[N],num[N],top=0,minn[N],n,d,m;
    bool fl[N];
    int to[N<<1],nex[N<<1],head[N],tot=0,w[N<<1],du[N];
    void add(int a,int b){ to[++tot]=b; nex[tot]=head[a]; head[a]=tot; }
    vector<int>kk[N];
    void tarjan(int x)
    {
        vis[x]=low[x]=++T;
        stk[++top]=x; fl[x]=true;
        for(int i=head[x];i;i=nex[i]){
            if(w[i]==-1) continue;
            int v=to[i];
            if(!vis[v]){ tarjan(v); low[x]=min(low[x],low[v]); }
            else if(fl[v]) low[x]=min(low[x],vis[v]);
        }
        if(vis[x]==low[x]){
            cnt++;
            do{
                fl[stk[top]]=false; bel[stk[top]]=cnt;
                kk[cnt].push_back(stk[top]); 
                num[cnt]++; minn[cnt]=min(minn[cnt],stk[top]);
            }while(stk[top--]!=x);
        }
    }
    void work()
    {
        queue<int>q;
        for(int i=1;i<=n;i++) if(du[i]<d) q.push(i);
        while(!q.empty()){
            int u=q.front(); q.pop();
            for(int i=head[u];i;i=nex[i]){
                int v=to[i];
                if(w[i]==-1) continue;
                du[v]--; w[i]=-1;
                if(du[v]<d) q.push(v);
            }
        }
    }
    int main()
    {
        freopen("party.in","r",stdin);
        freopen("party.out","w",stdout);
        int a,b;
        scanf("%d%d%d",&n,&m,&d);
        for(int i=1;i<=m;i++){
            scanf("%d%d",&a,&b);
            add(a,b); add(b,a);
            du[a]++; du[b]++;
        }
        work();
        memset(minn,0x7f7f7f,sizeof(minn));
        for(int i=1;i<=n;i++)
        if(!vis[i]) tarjan(i);
        int ans=0,mn=0x7f7f7f;
        for(int i=1;i<=cnt;i++)
        if(num[i]>num[ans]||(num[i]==num[ans]&&minn[i]<mn)) mn=minn[i],ans=i;
        printf("%d
    ",num[ans]);
        for(int i=1;i<=n;i++)
        if(bel[i]==ans) printf("%d ",i);
    }
    /*
    18 25 3
    9 11
    1 15
    13 15
    3 1
    7 16
    11 13
    17 6
    3 13
    5 1
    7 2
    4 15
    7 6
    11 3
    5 10
    9 16
    6 5
    7 1
    7 3
    17 16
    1 7
    3 1
    5 8
    3 9
    3 7
    1 12
    
    */
  • 相关阅读:
    [CetOS7]ssh信任
    Qt 路径中常用字符“./”、“../”、“/”、“*”的含义
    C++ fgets函数
    时间函数QueryPerformanceFrequency
    C++snprintf的使用
    提高C/C++运行效率以及避免出现Bug的20种方法
    Git 基本使用方法
    Eigen 矩阵基本运算
    Qt 断言Q_ASSERT的使用
    Qt QChart使用指南
  • 原文地址:https://www.cnblogs.com/mowanying/p/11402303.html
Copyright © 2020-2023  润新知