zoukankan      html  css  js  c++  java
  • 暑假考试题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
    
    */
  • 相关阅读:
    论频谱中负频率成分的物理意义(转载)
    VS2008的glaux库
    通过域名显示IP列表
    Shader errorX3205的解决
    Curl, Divergence, Circulation
    关于FIONREAD命令的作用
    Cairngorm的结构及开发使用(2)(转)
    结合Flex Builder和Flash CS4制作一个中国地图的应用(转)
    大型高并发高负载网站的系统架构(转)
    Cairngorm的结构及开发使用(4)(转)
  • 原文地址:https://www.cnblogs.com/mowanying/p/11402303.html
Copyright © 2011-2022 走看看