机会问题题解

long_hao 2022-02-22 17:25:18 2022-02-23 16:43:17

现在的数据应该没错,我的算法很复杂(指可能是WA)

代码如下

#include<bits/stdc++.h>
using namespace std;
int n,m,a,b,c,ans,ans1,iu,ans2;
struct edge{
	int bian,happy,use,now,nowh;
};
const int p=1e4+10;
edge g[p];
int v[p];
void work(int cur,int x,int happy)
{
	if(cur>n-1)
	{
		return;
	}
	for(int i=1;i<=m;i++)
	{
		if(i==x)
		{
			g[x].now*=1.2;
			g[x].nowh*=0.9;
			if(cur+g[i].now<=n-1)
			{
				work(cur+g[i].now,i,happy+g[i].nowh);
			}
			g[x].now=g[x].use;
			g[x].nowh=g[x].happy;
			continue;
		}
		if(cur+g[i].now<=n-1)
		{
			int a=g[x].now;
			int b=g[x].nowh;
			g[x].now=g[x].use;
			g[x].nowh=g[x].happy;
			work(cur+g[i].now,i,happy+g[i].nowh);
			g[x].now=a;
			g[x].nowh=b;
		}
	}
	if(happy>ans)
	{
		ans=max(ans,happy);
		ans1=cur;
	}
}
bool work1(int cur,int x,int happy)
{
	
	if(happy==ans)
	{
		return 1;
	}
	for(int i=1;i<=m;i++)
	{
		if(i==x)
		{
			g[x].now*=1.2;
			g[x].nowh*=0.9;
			if(cur+g[i].now<=n-1)
			{
				v[i]++;
				work1(cur+g[i].now,i,happy+g[i].nowh);
				v[i]--;
			}
			g[x].now=g[x].use;
			g[x].nowh=g[x].happy;
			continue;
		}
		if(cur+g[i].now<=n-1)
		{
			v[i]++;
			work1(cur+g[i].now,i,happy+g[i].nowh);
			v[i]--;
		}
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&a,&b,&c);
		g[i].bian=a;
		g[i].happy=b;
		g[i].use=c;
		g[i].now=c;
		g[i].nowh=b;
	}
	for(int i=1;i<=m;i++)
	{
		if(g[i].now<=n-1)
		{
			v[i]++;
			work(g[i].now,i,g[i].nowh);
			v[i]--;
		}
	}
	for(int i=1;i<=m;i++)
	{
		if(g[i].now<=n-1)
		{
			v[i]++;
			if(work1(g[i].now,i,g[i].nowh))
			{
				break;
			}
			v[i]--;
		}
	}
	for(int i=1;i<=m;i++)
	{
		int t=iu;
		iu=max(iu,v[i]);
		if(t!=iu)
		{
			ans2=i;
		}
	}
	cout<<ans<<" "<<ans2<<" "<<ans1;
	return 0;
}

暴力万岁!

因为涉及到重复选取,第一次选取是很正常的初始数据,第二次会叠加一层buff,第三次会叠加两层的buff,以此类推,并要求输出活动最多的编号,消耗的机会值。

题目中有个小坑,提到了 机会不能用完 的概念,其实也好解决,让输入的机会值直接减去一个一就可以了,让最大可用机会就是n-1,虽然可能用不完,但是不会爆掉。

首先读入编号等东西,让每个值都运行一次work,求出最大的快乐值happy,x代表上一次的选择(当前层数的选择),cur代表消耗的机会。

用now来代表现在的消耗值,nowh代表现在这个机会活动的快乐值。因为题中“强制类型转换int”就不需要开double来计算,每一次让所有的活动都进行递归if(x==i)当中还原now,nowh是在于选完之后要及时还原,不影响没选的时候的情况,如果选择的不是上一次连续做过的活动,那么它的值应该回归初始值,让now等于use,nowh等于happy

计算出最大的快乐ans,消耗ans1之后,因为我是蒟蒻,所以又打了一个work2,求出当时选择的路程,定一个数组v,让每一个i去v[i]++,并及时还原,求到当前happy等于ans的时候,就说明已经求到了之前work求出的最大快乐。(数据很弱,所以还在时间范围内,并且不存在有两种快乐值相等的情况)

并且求出来之后返回一个1,立即停止主函数中的遍历,因为此时v[i]--的话会导致错误,这个时候的i是要累加的,不可以减去。

最后遍历一遍v,求出数值最大的编号,cout这三个数值,结束。