Codeforces Round #661 (Div. 3)E1. Weights Division (easy version)题解(dfs树遍历+贪心))

小叙:图论一直是我的弱项,在这几场的cf中没到图论就被卡住,本博主一直在补图论方面的知识,希望下场cf能AC一道图论题。

E1. Weights Division (easy version)

题意:

  • 给你一棵顶点为1,点数为n的树,每条边都有一个权值 w w w
  • 我们有一种操作,使得一条边的 w w w变成 w / 2 w/2 w/2向下取整。
  • 现在给你一个值 S S S使得,从顶点1到每个叶子节点路径之和 < = S <=S <=S
  • 问最少要操作几次才能符合题目要求。

题解:

  • 这个数的权值总和 = = =每条边的权值 w × w× w×当条边被访问过的次数(从顶点1到每个叶子结点路径上)。
  • 我们肯定优先找到当前能减少( c n t ∗ w − c n t ∗ ( w / 2 ) cnt * w - cnt * (w/2) cntwcnt(w/2))最多的去操作。这时候我们就需要用优先队列来处理。
  • 一直重复操作2知道符合题干。

ACcode1:

/*
 * @Author: NEFU_马家沟老三
 * @LastEditTime: 2020-08-06 18:11:03
 * @CSDN blog: https://blog.csdn.net/acm_durante
 * @E-mail: [email protected]
 * @ProbTitle: 树遍历+贪心
 */
#include 
using namespace std;
typedef long long ll;
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, a, n) for (int i = n; i >= a; i--)
#define lowbit(x) ((x) & -(x))
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#define mem(a, b) memset(a, b, sizeof(a))
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const double PI = acos(-1.0);
const ll mod = 1e9 + 7;
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
template<class T>inline void read(T &res)
{
char c;T flag=1;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
}
int n;
const int N = 1e5+5;
int w[N],cnt[N];
struct edge
{
    int to,id;//id为边的编号
};
ll s;
vector<edge>e[N];//邻接链表
//now是当前节点编号,front为now上一节点与now所连接边的编号
void dfs(int now,int front){
    if(e[now].size()==1){
        cnt[front] = 1;
    }

    for(auto x:e[now]){
        int to = x.to ,id = x.id;
        if(id == front) continue;
        dfs(to,id);
        if(front!=0) cnt[front]+=cnt[id];
    }
}
struct node
{
    ll e_w,cnt_e;
    bool operator <(const node &A) const{
        return e_w * cnt_e - e_w / 2 * cnt_e < A.e_w * A.cnt_e - A.e_w / 2 * A.cnt_e;
    }
};

priority_queue<node>q;//优先队列

int main()
{
    IOS
    int t;
    cin >> t;
    while (t--)
    {
        cin >> n >> s;
        rep(i,1,n) e[i].clear();
        while(!q.empty()) q.pop();
        mem(cnt,0);
        rep(i,1,n-1) {
            int x,y;
            cin >> x >> y >> w[i];
            e[x].push_back({y,i});
            e[y].push_back({x,i});
        }
        dfs(1,0);
        ll sum = 0;
        ll ans = 0;
        rep(i,1,n-1){
            q.push({(ll)w[i],(ll)cnt[i]});
            sum += w[i]*1ll*cnt[i];
        }
        while(sum > s){
            ans++;
            ll ww = q.top().e_w, cc= q.top().cnt_e;
            q.pop();
            q.push({ww/2,cc});
            sum = sum - cc*(ww) + cc*(ww/2);
        }
        cout << ans << '\n';
    }
    return 0;
}

ACcode2:

/*
 * @Author: NEFU_马家沟老三
 * @LastEditTime: 2020-08-06 18:13:47
 * @CSDN blog: https://blog.csdn.net/acm_durante
 * @E-mail: [email protected]
 * @ProbTitle: 
 */
#include 
using namespace std;
typedef long long ll;
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, a, n) for (int i = n; i >= a; i--)
#define lowbit(x) ((x) & -(x))
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#define mem(a, b) memset(a, b, sizeof(a))
const double PI = acos(-1.0);
const int N = 2e5+5;
struct Edge
{
    int v,next,w;
}e[N];
int head[N>>1];
int cnt;
void add(int u,int v,int w){
    e[++cnt].v = v;
    e[cnt].w = w;
    e[cnt].next = head[u];
    head[u] = cnt;
}//链式前向星

struct node
{
    ll w,cnt;
    bool operator<(const node &A)const{
        return cnt * w - cnt * (w>>1) < A.cnt * A.w - A.cnt * ( A.w>>1 );
    }
};
ll sum = 0;
priority_queue<node>q;
int dfs(int u,int fa){
    int u_cnt = 0;//以当前节点为根的子树中节点的个数
    for(int i = head[u]; ~i ; i = e[i].next){
        int v = e[i].v , w = e[i].w;
        if(v == fa) continue;
        int son_cnt = dfs(v,u); //v为子树子节点个数
        q.push({(ll)w,(ll)son_cnt});//存入优先队列
        sum += son_cnt * 1ll * w;
        u_cnt += son_cnt;
    }
    return u_cnt ? u_cnt : 1;//u_cnt为0则是叶子,需要返回1
}
int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int t;
    cin >> t;
    while(t--){
        int n; ll s;
        cnt = 0;//链式前向星pos
        sum = 0;
        mem(head,-1);
        while(!q.empty()) q.pop();
        cin >> n >> s;  
        rep(i,1,n - 1){
            int u,v,w;
            cin >> u >> v >> w;
            add(u,v,w);
            add(v,u,w);    
        }
        dfs(1,-1);
        ll ans = 0;
        while(sum > s){
            ++ans;
            ll w = q.top().w , c = q.top().cnt;
            q.pop(),q.push({w>>1,c});
            sum = sum - c * w + c * (w>>1);
        }
        cout << ans << '\n';
    }
    return 0;
}

你可能感兴趣的:(Codeforces之旅,ACM&图论)