1298. 通讯问题

1298. 通讯问题

★   输入文件:jdltt.in   输出文件:jdltt.out   简单对比
时间限制:1 s   内存限制:128 MB

【题目描述】

一个篮球队有n个篮球队员,每个队员都有联系方式(如电话、电子邮件等)。但并不是每个队员的联系方式都公开,每个队员的联系方式只有一部分队员知道。问队员可以分成多少个小组,小组成员之间可以相互通知(包括一个队员一个组,表示自己通知自己)。

【输入格式】

 

输入文件有若干行

第一行,一个整数n,表示共有n个队员(2<=n<=100)

下面有若干行,每行2个数a、b,a、b是队员编号,表示a知道b的通讯方式。

【输出格式】

输出文件有若干行

第一行,1个整数m,表示可以分m个小组,下面有m行,每行有若干个整数,表示该小组成员编号,输出顺序按编号由小到大。

 

【样例输入】

12
1 3
2 1
2 4
3 2
3 4
3 5
4 6 
5 4
6 4
7 4
7 8
7 12
8 7
8 9
10 9
11 10

 

【样例输出】

8

1 2 3

4 6

5

7 8

9

10

11

12

 

暴力代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
int n,m,k,x,y;
#define N 110
int a[N][N],b[N/2][N],vis[N],jl[N],zj=0,tot=0,t1=0,qi;
void bj(int z){
    for(int i=0;i<zj;i++)
       vis[jl[i]]=1;
    sort(jl,jl+zj);
    zj=unique(jl,jl+zj)-jl;
    for(int i=0;i<zj;i++)
      b[jl[0]][i]=jl[i];
    tot++;
    for(int i=0;i<zj;i++) jl[i]=0;
    zj=0;
}
void dfs(int u,int v){
    if(vis[u]||vis[v]||u==v) return;
    if(v==qi) {bj(zj); return;}
    if(a[u][v]&&!vis[v]) {
        jl[zj++]=v;
        for(int j=1;j<=n;j++){
            if(a[v][j]&&!vis[j])
              dfs(v,j);
        }
    }
    if(u==qi&&zj>0) zj--;
}
int main()
{
    freopen("jdltt.in","r",stdin);
    freopen("jdltt.out","w",stdout);
    scanf("%d",&n);
    while(scanf("%d%d",&x,&y)==2){
        a[x][y]=1;
    }
    for(qi=1;qi<=n;qi++){
        for(int j=1;j<=n;j++)
        if(qi!=j&&a[qi][j]){
           if(!vis[qi]){
                 if(!vis[j]){
                     jl[zj++]=qi;
                dfs(qi,j);
                }else continue; 
           }else break;
           
        }
    }
    for(int i=1;i<=n;i++) 
       if(!vis[i]) t1++;
    printf("%d\n",t1+tot);
    for(int i=1;i<=n;i++){
        if(b[i][0]!=0){
            for(int j=0;b[i][j];j++){
                printf("%d ",b[i][j]);
            }
            printf("\n");
        }
        else if(!vis[i])
                printf("%d\n",i);
        
    }
    return 0;
}

 暴力代码虽然ac(数据太水),但有bug;

例如

输入数据
5
1 2
2 3
3 1
2 4
4 5
5 1

正确输出
1
1 2 3 4 5

然而 不对;

正确tarjan算法:(一样ac)

#include<cstdio>
#include<iostream>
#include<vector>
#include<stack>
#include<algorithm>
#define M 100010
#define N 2010
using namespace std;
vector<int> grap[M];
stack<int> s;
int low[M],num[M],vis[M],instack[M];
int index,cnt,n;
struct node{
    int sum;
    int dl[N];
    void px()
    {
        sort(dl+1,dl+sum+1);
    }
};node f[N];
int cmp(const node&x,const node&y)
{
    return x.dl[1]<y.dl[1];
}
void tarjan(int v)
{
    low[v]=num[v]=++index;
    s.push(v);
    instack[v]=1;
    vis[v]=1;
    for(int i=0;i<grap[v].size();i++){
        int w=grap[v][i];
        if(!vis[w]){
            tarjan(w);
            low[v]=min(low[v],low[w]);
        }
        else if(instack[w])
          low[v]=min(low[v],num[w]);
    }
    int u;
    if(low[v]==num[v]){
        ++cnt;
        do
        {
            u=s.top();
            f[cnt].dl[++f[cnt].sum]=u;
            s.pop();
            instack[u]=0;
        }while(u!=v);
    }
}
int main()
{
    freopen("jdltt.in","r",stdin);
    freopen("jdltt.out","w",stdout);
    int x,y;
    scanf("%d",&n);
    while(scanf("%d%d",&x,&y)==2)
       grap[x].push_back(y);
    for(int i=1;i<=n;i++)
       if(!vis[i])tarjan(i);
    printf("%d\n",cnt);
    for(int i=1;i<=cnt;i++)
       f[i].px();
    sort(f+1,f+cnt+1,cmp);
    for(int i=1;i<=cnt;i++){
        for(int j=1;j<=f[i].sum;j++)
           printf("%d ",f[i].dl[j]);
        printf("\n");
    }
    return 0;
}

 

posted @ 2016-05-15 19:31  神犇(shenben)  阅读(215)  评论(0编辑  收藏  举报