CF316B1 EKG dfs+01背包

CF316B1 EKG

题意:

一个医院有n个人排了一些队伍,每个人编号从1~n依次排列。一个人只知道站在他前面人的编号,有一些人忘记了自己前面人的编号。现在给出n个人和队伍中一个人的编号pos,要求依次输出编号为pos的人在队伍中所有可能站的位置。(队伍中不可能有环)

思路:

因为明确给出队伍不会成环,则发现每个队伍的尽头总会是0,所以利用dfs搜索把每个队伍的长度搜索出来。找的过程中特别记录点pos在所在队伍的位置。因为多个队伍所构成的链的长度组成方式有多种,这刚好与01背包的原理完全相同,所以使用动态规划枚举每一种情况。最终输出即可。该题最终时间复杂度为O(n2)

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <functional>
#include <set>
#define int long long
#define MAXN 2000
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
using namespace std;
int arr[MAXN];
int arr2[MAXN];
bool vis[MAXN];
int flag[MAXN];
int val;
bool ff = 0;
int cnt;
//深搜查找链的长度
int dfs(int n,int pos,int cnt1) {
	//若找到了点pos所在的位置则不需要继续向下寻找,直接记录点pos在这个链到第一个人的长度即可
	if (n == pos) {
		ff = 1;
		val = cnt1 + 1;
		return 0;
	}
	else if (n==0) {
		cnt = cnt1;
		return 0;
	}
	++cnt1;
	dfs(arr[n],pos,cnt1);
	return 0;
}
signed main() {
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int n, pos;
	int k = 0;
	int kk = 0;
	cin >> n >> pos;
	for (int i = 1; i <= n; ++i) {
		cin >> k;
		if (k!=0) {//记录第k个人前面的人i
			arr[k] = i;
			vis[i] = 1;
		}
	}//遍历一遍0的链,并找到链的长度。
	for (int i = 1;i<=n;++i) {
		ff = 0;
		if (vis[i]==0) {
			dfs(i, pos, 0);
			if (ff==0) {
				arr2[++kk] = cnt;
			}
		}
	}
	//找到所有链的长度后,找到所有链的组合方式,记录每种组合下链的长度
	//此方法和01背包方法完全相同
	flag[0] = 1;
	for (int i = 1;i<=kk;++i) {//一维空间压缩
		for (int j = n;j>=arr2[i];--j) {
			flag[j] = max(flag[j - arr2[i]], flag[j]);
		}
	}
	for (int i = 0;i<=n;++i) {//遍历所有情况
		if (flag[i]==1) {
			cout << i+val << endl;
		}
	}
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值