L2-020 功夫传人 (25分)(双解法 完整思路+极短代码)

在这里插入图片描述
首先捋一下题,给了一个初始值,然后没传一代就减少一点,如果是得到者就让他获得的功力乘以倍数,最后求得到者功力总和。那么也就是说我们需要找两个东西:1.得到者 2.得到者是第几代。

思路一:建立一个二维动态数组,然后在输入的时候横坐标代表这个人的编号,这一行就存储它的徒弟的编号。如果是得到者的话就只存储它的倍数,顺便建立一个标记数组将对应编号标记为1(原先为0).这样接收完数据后。之间开始DFS,只要该行下标不是被标记的行就挨着搜索就行。代码如下:

#include<bits/stdc++.h>
using namespace std;
int n,k,x,vis[100010];
double sum,z,r;
vector<vector<int>>v;
void dfs(int index,double power)
{
	if(vis[index])
	{
		sum+=power*v[index][0];
		return ;
	}
	for(int i=0;i<v[index].size();i++)
		dfs(v[index][i],power*(1-r/100));
}
int main()
{
	cin>>n>>z>>r;
	v.resize(n);
	for(int i=0;i<n;i++)
	{
		cin>>k;
		if(!k)
		{
			cin>>x;
			vis[i]=1;
			v[i].push_back(x);
		}
		while(k--)
		{
			cin>>x;
			v[i].push_back(x);
		}
	}
	dfs(0,z);
	cout<<(int)sum;
}
	

思路二:相对于思路一,我个人更偏向于这种解法,虽然技术含量不高,但是易于理解。精髓就在于接收数据将得到者的下标和倍数存到一个队列中(数组也可以,个人习惯)。然后不是得到者的用一个pre数组来存储它的前驱结点(就是它的师父)。这样接收完数组后,只有pre[i]==i的点是祖先。然后我们开始遍历队列,
每次取队头,然后根据pre数组找他是第几代,最后就可以算出来这个得到者获得了多少功力,代码如下:

#include<bits/stdc++.h>
using namespace std;
struct node
{
	int p,index;
};
int n,k,x,pre[100010],root;
queue<node>q;
double z,r,sum;
double deal()
{
	while(!q.empty())
	{
		node u=q.front();
		q.pop();
		int cnt=0,a=u.index;
		while(pre[a]!=a)
		{
			a=pre[a];
			cnt++;
		}
		sum+=z*pow(1-r/100,cnt)*u.p;
	}
	return sum;
}		
int main()
{
	cin>>n>>z>>r;
	for(int i=0;i<n;i++)	pre[i]=i;
	for(int i=0;i<n;i++)
	{
		cin>>k;
		if(!k)
		{
			cin>>x;
			q.push({x,i});
		}
		while(k--)
		{
			cin>>x;
			pre[x]=i;
		}
	}
	cout<<deal();
}

发布了180 篇原创文章 · 获赞 22 · 访问量 9014

猜你喜欢

转载自blog.csdn.net/qq_44622401/article/details/104267213