vijos P1021,P1022,p1023 Victoria的舞会1,2,3题解

来源:互联网 发布:虚拟机上安装linux 编辑:程序博客网 时间:2024/05/29 18:01

Victoria的舞会1:

Description

  Victoria是一位颇有成就的艺术家,他因油画作品《我爱北京天安门》闻名于世界。现在,他为了报答帮助他的同行们,准备开一个舞会。   Victoria准备邀请n个已经确定的人,可是问题来了:   这n个人每一个人都有一个小花名册,名册里面写着他所愿意交流的人的名字。比如说在A的人名单里写了B,那么表示A愿意与B交流;而且如果A名单里面有B,那么B名单里面肯定有A,也就是说两个人如果一方愿意和另一方交流,那么另一方也肯定愿意和这一方交流。   Victoria觉得需要在这n个人里面确定m个人,保证这m个人每一个人都能在舞会中找到至少k个人交流,并求出一种方案以确定m的最大值是多少。   注意:自己的名单里面不会有自己的名字。

Input

第一行两个数n和k。接下来n行,每i+1行表示编号为i的人的小花名册名单,名单以0结束。1< =n,k< =200。

Output

一个数,m。

Sample Input

22 1
4 5 10 11 20 21 0
2 3 6 8 11 16 0
2 3 5 8 12 15 16 18 0
1 5 6 10 11 12 16 18 0
1 3 4 16 20 0
2 4 19 21 22 0
8 9 13 19 20 0
2 3 7 10 19 0
7 10 14 16 19 0
1 4 8 9 10 20 0
1 2 4 18 19 20 21 0
3 4 13 0
7 12 15 16 18 19 21 22 0
9 16 0
3 13 21 0
2 3 4 5 9 13 14 20 0
18 22 0
3 4 11 13 17 21 0
6 7 8 9 11 13 19 21 22 0
1 5 7 10 11 16 21 22 0
1 6 11 13 15 18 19 20 0
6 13 17 19 20 0

Sample Output

22


第一题大水,拿数组就行了,并查集也可以.

#include<stdio.h>   int main()  {       int s,n,k,x,ans=0,i;      scanf("%d%d",&n,&k);     for(i=1;i<=n;i++){          x=0;          while(scanf("%d",&s)==1&&s!=0)              x++;          if(x>=k)              ans++;      }      printf("%d",ans);    }






Victoria的舞会2:

这个就需要强联通分量个数.

Description

 Victoria是一位颇有成就的艺术家,他因油画作品《我爱北京天安门》闻名于世界。现在,他为了报答帮助他的同行们,准备开一个舞会。

  Victoria准备邀请n个已经确定的人,可是问题来了:

  这n个人每一个人都有一个小花名册,名册里面写着他所愿意交流的人的名字。比如说在A的人名单里写了B,那么表示A愿意与B交流;但是B的名单里不见得有A,也就是说B不见得想与A交流。但是如果A愿意与B交流,B愿意与C交流,那么A一定愿意与C交流。也就是说交流有传递性。

  Victoria觉得需要将这n个人分为m组,要求每一组的任何一人都愿意与组内其他人交流。并求出一种方案以确定m的最小值是多少。

  注意:自己的名单里面不会有自己的名字。

Input

第一行一个数n。接下来n行,每i+1行表示编号为i的人的小花名册名单,名单以0结束。1< =n< =200。

Output

一个数,m。

Sample Input

18
0
18 0
0
0
11 0
0
0
0
0
0
5 0
0
0
0
0
0
0
2 0

Sample Output

16
#include<stdio.h>int n;int idx;int low[401];int deep[401];int z[401];int top,tot;int v[401];int inz[401];int f[401][401];int a[401][401],ans;int min(int x,int y){if(x>y)return y;return x;}void tarjan(int x){    z[++top]=x;v[x]=1;inz[x]=1;    deep[x]=low[x]=++tot;            for(int i=1;i<=n;i++)        if(a[x][i]==1)        {            if(v[i]==0)  tarjan(i),low[x]=min(low[x],low[i]);                else if(inz[i]==1)  low[x]=min(low[x],deep[i]);            }    if(deep[x]==low[x])    {        ans++;        int t;        do        {            t=z[top--],inz[t]=0;                       f[ans][++f[ans][0]]=t;            }while(t!=x);    }}int main(){int b,c,m;scanf("%d",&n);for(int i=1;i<=n;i++){while(scanf("%d",&b)==1){if(b!=0)a[i][b]=1;elsebreak;}}    for(int i=1;i<=n;i++)        if(!deep[i])            tarjan(i);printf("%d",ans);}

Victoria的舞会3:

此题需要求缩点

Description

  Victoria是一位颇有成就的艺术家,他因油画作品《我爱北京天安门》闻名于世界。现在,他为了报答帮助他的同行们,准备开一个舞会。

  Victoria准备邀请n个已经确定的人,可是问题来了:

  这n个人每一个人都有一个小花名册,名册里面写着他能够通知到的人的名字。比如说在A的人名单里写了B,那么表示A能够通知到B;但是B的名单里不见得有A,也就是说B不见得通知到A。

  Victoria觉得需要确定自己需要通知多少个人m,能够实际将所有人n都通知到。并求出一种方案以确定m的最小值是多少。

  注意:自己的名单里面不会有自己的名字。Victoria可以自身通知到所有n个人。

Input

第一行一个数n。接下来n行,每i+1行表示编号为i的人的小花名册名单,名单以0结束。1< =n< =200。

Output

一个数,m。

Sample Input

18
0
11 0
0
0
0
16 0
140
0
0
0
2 13 0
0
11 0
7 0
0
6 0
0
0

Sample Output

14


#include<stdio.h>int head[201];int to[401],n;int next[401];int idx;int low[401];int deep[401];int z[401];int top,tot;int v[401];int inz[401];int f[401][401];int a[401][401],ans;int belong[401];int du[401];int min(int x,int y){if(x>y)return y;return x;}void tarjan(int x){    z[++top]=x;v[x]=1;inz[x]=1;    deep[x]=low[x]=++tot;            for(int i=1;i<=n;i++)        if(a[x][i]==1)        {            if(v[i]==0)  tarjan(i),low[x]=min(low[x],low[i]);                else if(inz[i]==1)  low[x]=min(low[x],deep[i]);            }    if(deep[x]==low[x])    {        ans++;        int t;        do        {            t=z[top--],inz[t]=0;                       f[ans][++f[ans][0]]=t;            }while(t!=x);    }}int main(){int b,c,m,cnt=0;scanf("%d",&n);for(int i=1;i<=n;i++){while(scanf("%d",&b)==1){if(b!=0)a[i][b]=1;elsebreak;}}    for(int i=1;i<=n;i++)        if(!deep[i])            tarjan(i);for(int i=1;i<=ans;i++)for(int j=1;j<=f[i][0];j++)belong[f[i][j]]=i;   for(int i=1;i<=n;i++)   for(int j=1;j<=n;j++)   {   if(a[i][j]==1&&belong[i]!=belong[j])du[belong[j]]++;   }    for(int i=1;i<=ans;i++)    if(du[i]==0)    cnt++;printf("%d",cnt);}


原创粉丝点击