[Codeforces Round #661 (Div. 3)] E1.Weights Division (easy version)

题目链接:E1.Weights Division (easy version)

可能这几天没练基础思维题导致前面签到题打得慢,关键均题WA1发,又关键有两道题败在输入输出上,很不应该,后面等牛客完了,补补cf的题,提升一下自己的代码能力。

题意

题意是给你n个节点带边权的树,给你一个数S,你可以选一些边然后将其权值变为其一半向下取整,然后问你最少进行多少次操作使得从根节点到所有叶结点的权值之和小于等于S。

题解

我们来分析题意,从根节点到所有叶结点的权值之和包含哪些部分,首先一部分是边权值,但很显然这是仅仅不够的,因为你把所有的边权值加起来并不是从根节点到所有叶结点的权值之和,其中有些边会被计算多次。所以我们还需要统计每条边被计算的个数。
这样我们首先知道了自己需要统计哪些变量。

  1. 从根节点出发,到所有叶子结点每条边被经过了多少次。
  2. 知道了次数和边权值,我们就可以统计 s u m = ∑ i = 1 n − 1 w [ i ] ∗ t i m e s [ i ] {sum=\sum_{i=1}^{n-1}w[i]*times[i]} sum=i=1n1w[i]times[i](i为边的编号),同时也可以将 w [ i ] 和 t i m e s [ i ] {w[i]和times[i]} w[i]times[i]打包存储在一个数组里方便后面进行操作。

统计完变量后,我们可以贪心考虑如何进行操作,如果sum>S,那么就从最大的边开始,我们此时可以搞一个优先队列,将刚刚打包的w[i]和times[i]存入优先队列里,那么优先等级是什么?由于每次被选的边权值会变为 ⌊ w [ i ] / 2 ⌋ {\lfloor w[i]/2\rfloor} w[i]/2,那么sum总和就减少 ( w [ i ] − ⌊ w [ i ] / 2 ⌋ ) ∗ t i m e s [ i ] {(w[i]-\lfloor w[i]/2\rfloor)*times[i]} (w[i]w[i]/2)times[i],为了操作数更少,我们需要每次对sum减少的应该尽可能多,所以优先级就为 ( w [ i ] − ⌊ w [ i ] / 2 ⌋ ) ∗ t i m e s [ i ] {(w[i]-\lfloor w[i]/2\rfloor)*times[i]} (w[i]w[i]/2)times[i]。这样每次我们取出来的边一定是使sum减少最多的。

代码

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
//extern "C"{void *__dso_handle=0;}
typedef long long ll;
typedef long double ld;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define pii pair

const double PI=acos(-1.0);
const double eps=1e-6;
const ll mod=1e9+7;
const int inf=0x3f3f3f3f;
const int maxn=1e5+10;
const int maxm=100+10;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);


ll dis[maxn],sum=0;
int times[maxn];
vector<pii> num;

struct edge
{
	int to,w;
	edge(int to,int w){
		this->to=to;
		this->w=w;
	}
};
vector<edge> g[maxn];

void dfstimes(int u,int f)
{
	if(g[u].size()==1 && g[u][0].to==f)
	{
		times[u]=1;
		return ;
	}
	for(int i=0;i<g[u].size();i++)
	{
		int v=g[u][i].to;
		if(v==f) continue;
		dfstimes(v, u);
		times[u]+=times[v];
	}
}

void dfsum(int u,int f)
{
	if(g[u].size()==1 && g[u][0].to==f) return ;
	for(int i=0;i<g[u].size();i++)
	{
		edge v=g[u][i];
		if(v.to==f) continue;
		num.pb(mp(v.w,times[v.to]));
		sum+=(ll)v.w*times[v.to];
		dfsum(v.to, u);
	}	
}
struct cmp{
	bool operator() (const pii a,const pii b)
	{
		return (a.first-a.first/2)*a.second < (b.first-b.first/2)*b.second;
	}
};

int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		sum=0;
		memset(g, 0, sizeof(g));
		memset(times, 0, sizeof(times));
		num.clear();
		int n;
		ll s;
		scanf("%d%lld",&n,&s);
		for(int i=0;i<n-1;i++)
		{
			int u,v,w1;
			scanf("%d%d%d",&u,&v,&w1);
			g[u].pb(edge(v,w1));
			g[v].pb(edge(u,w1));
		}
		dfstimes(1,-1);
		dfsum(1, -1);
		priority_queue<pii,vector<pii>,cmp > que;
		for(int i=0;i<num.size();i++) que.push(num[i]);
		ll cnt=0;
		while(sum>s)
		{
			cnt++;
			pii tmp=que.top();
			que.pop();
			sum-=(tmp.first-tmp.first/2)*tmp.second;
			tmp.first/=2;
			que.push(tmp);
		}
		printf("%lld\n",cnt);
	}
}

你可能感兴趣的:(贪心,DFS搜索)