P2835 刻录光盘 做题记录

首先我想到这个办法的原因是前一天晚上做的那个B题,所以有这样的解法

我的解决方法大概是,他们有前后连接关系,跟图一样,我只要找有几个独立的图就行。

不明白啥是图的当地点和地点之间的连接的路就行,一些地方和另一些地方没有路可以到达,即使我借助其他的地方中转也算一张图上的点

解决的时候我犯得第一个错误没注意到只有一个路径和多个路径的区别。(没看懂这个代码没关系,我下面会讲一下思路,最下面讲如何实现)

#include<stdio.h>
int mark[100000];
int pd[1000000];
struct node{
	int to;
	int next;
}list[1000000];
int cnt=1;
int head[10000];
void add(int p,int to){
	list[cnt].to=to;
	list[cnt].next=head[p];
	head[p]=cnt++;
}
int sum=0;
int n,a;
void dfs(int i){
	if(mark[i]==1){
		return ;
	}
	mark[i]=1;
	int l=head[i];
	while(l){
		dfs(list[l].to);
		l=list[l].next;
	}
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		while(1){
			scanf("%d",&a);
			if(a==0){
				break;
			}
			add(i,a);
			pd[a]=1;
		}
	}
	for(int i=1;i<=n;i++){
		if(pd[i]==0){
			dfs(i);
			sum++;
		}
	}
	for(int i=1;i<=n;i++){
		if(mark[i]==0){
			dfs(i);
			sum++;
		}
	}
	printf("%d",sum);
}

先找入度为0的点(就是直接和这个点连接的路径的个数为0),每个入度为0的点都得个一个光盘,然后还有一些点不在这些范围里面,那就是一定是环(先去想明白,环所在的图不一定没有入度的点,所以由上面那些点跑一遍,可能走过一些环了,而且在里面环不一定是那种所有点在一个圈上的那种,是这个环)

所以状态就从所有入度为0的点跑完,剩下的看还有多少环,每个环给一个光盘,这样就可以找到答案了。

但是,咋去找没有入度为零的情况,我上面第一次交的代码有问题,因为它是单向的图,所有我如果出现上图右边上面那种情况的图,就有可能多算(如果先找一个点在那个线上,再一个点在圈上,就会记录一次,实际上只给一个就行),但是把图看出无向图,会使左边那些情况有问题,

比如上面那个情况,如果当做无向图,应该给3个的,现在只记录了一次

所有上面的那个做法有问题,所以我先算有入度为0的按有向图算,然后算没有度为0拿无向图算,这样就解决了

我的实现方法是图和图的连接关系拿链式前向星存,然后再记录连接方式的同时,可以把有没有有点走向这个点的情况记录下来,然后我遍历一遍所有的点,pd数组里面为0的点都是入度为0的点,然后从这个点开始,走一遍,走过的点都再mark数组里面标记一下,然后算出来入度为0的个数有几个,你必须给它们一人一个光盘,然后再去图变成无向图,然后把所有全再找出来,就结束了。

#include<stdio.h>
int arr[1000000];
int mark[100000];
int pd[1000000];
struct node{
	int to;
	int next;
}list[1000000];
int cnt=1;
int head[10000];
void add(int p,int to){
	list[cnt].to=to;
	list[cnt].next=head[p];
	head[p]=cnt++;
}
int sum=0;
int n,a;
void dfs(int i){
	if(mark[i]==1||i==0){
		return ;
	}
	mark[i]=1;
	int l=head[i];
	while(l){
		dfs(list[l].to);
		l=list[l].next;
	}
}
int main(){
	scanf("%d",&n);
    for(int i=0;i<10000;i++){
    	list[i].to=0;
    }
	for(int i=1;i<=n;i++){
		while(1){
			scanf("%d",&a);
			if(a==0){
				break;
			}
			add(i,a);
			pd[a]=1;
		}
	}
	for(int i=1;i<=n;i++){
		if(pd[i]==0){
			dfs(i);
			sum++;
		}
	}
	for(int i=1;i<=n;i++){
		int l=head[i];
		while(l){
			add(list[l].to,i);
			l=list[l].next;
		}
	}
	for(int i=1;i<=n;i++){
		if(mark[i]==0){
			dfs(i);
			sum++;
		}
	}
	printf("%d",sum);
}

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值