计蒜客-鸣人的影分身之书 dfs序列

 

题目链接 https://www.jisuanke.com/course/709/36590

题意:有n个点,m条边的联通图,有m个人落在任一点上,往周围走。每个人最多经过2n/k个点,要求每个点都要被经过至少一次,求怎么走?

B站题解 https://www.bilibili.com/video/av9249649?from=search&seid=12541065912944045953

题解:DFS搜索一遍整个图,形成一个DFS序列,这个序列有2n-1个节点,将其分割给每个人即可,多余的人就随便走。

比如有下面这个图,从1开始dfs,则dfs序列可以是1->2->4->5->3->5->4->2->1,假如k=3,则第一个人走1->2->4->5,第二人走3->5->4->2,剩下的人走1即可

 

 

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define MAXN 400020
using namespace std;
int n,m,k;
struct Edge {
	int end;
	int next;
	Edge() {
		next = -1;
	}
} edge[MAXN];
int num = 0;// 记录边的数量 
bool visited[MAXN];
int head[MAXN];
int sequence[2*MAXN+10];// 记录dfs序列 
int snum = 0;

// 链式前向星加边 
void Add(int s,int e) {
	edge[num].next = head[s];
	head[s] = num;
	edge[num].end = e;
	num++;
}

// DFS搜索 
void DFS(int start) {
	visited[start] = true;
	sequence[snum++] = start;
	int i = head[start];
	// 搜索所有邻接点 
	for(;i != -1;i = edge[i].next) {
		// 访问过的点 
		if(visited[edge[i].end]) continue;		
		DFS(edge[i].end);
		sequence[snum++] = start;
	}	
}

int main() {	
	scanf("%d%d%d",&n,&m,&k);
	for(int i = 1;i <= n;i++)
		head[i] = -1;
	int u,v;
	for(int i = 0;i < m;i++) {
		scanf("%d%d",&u,&v);
		Add(u,v);
		Add(v,u);
	}
	DFS(1);
	int cnt = ceil(2*n*1.0/k);	
	int t = min(snum,cnt);
	printf("%d ",t);
	for(int i = 0;i < snum;i++) {
		t--;
		if(t > 0) {
			printf("%d ",sequence[i]);
		} else {
			printf("%d\n",sequence[i]);
			t = min(cnt,snum-i-1);
			k--;
			if(k && t > 0) {
				printf("%d ",t);				
			}
				
		}
	}
	
	if(k > 0) {
		for(int i = 0;i < k;i++) printf("1 %d\n",1);
	}
	
	return 0;
}

 

没有更多推荐了,返回首页