zoukankan      html  css  js  c++  java
  • Codeforces Round #633 (Div. 2) D. Edge Weight Assignment 思维or猜猜猜

    https://codeforces.ml/contest/1339/problem/D

    给定一个n个顶点的未加权的树,现在你要给每条边分配一个正权重,满足条件:树中每两个不同叶子节点之间的简单路径所有边权按位XOR值为0。

    可以放很大(无限大)的数,例如:10(1010),,,

    可以确保此类分配在给定约束条件下存在。

    定义 f 为叶子节点之间的简单路径上不同边权的数量。

    求 f 的最小值和最大值。

    例如:

    例1.

     第一棵树叶子节点1 -> 6之间不同的边权数量为1 (1),所有f=1。

     第二棵树叶子节点1 -> 6之间不同的边权数量为4 (1,2,4,7),所有f=4。

    f 最小值为1,最大值为4.

    例2.

    f 最小值最大值都为3.

     思路:首先思考最小值,偶数个相同的数异或为0,那么当俩叶子节点之间的边数为偶数时边权都相同就可以了,所以 f最小值为1;当边数出现奇数时,三个相同的数异或值肯定不为0,两个相同的数和一个不同的数异或也肯定不为0,那么就至少要三个不同的数异或,比如边数为5:那么就两个相同的数异或为0,三个不同的数来异或,使异或值为0,如:1^1^1^2^3.所以当边数为奇数时f最小值为3(不可能出现边数为1)。

    思考最大值:边数为2的话,这俩数肯定相等,边数不为2的情况,f 就等于边数(我也不知道为什么,猜猜猜,虽然树可能会长的很复杂很奇葩,但应该总能找到那么几个数异或等于0???题目特别说了权重可以非常大,hhhhhh,,,如果有大佬能证明的话,求告知)。

    总结:最小值只需要判断叶子节点之间的边数是否有奇数条就可以了,全偶数为1,有奇数为3;

    最大值只需找出边数为2的叶子节点,然后减去,先把 f 设为总边数(n-1),同一个节点连的叶子节点的数量为sum,那么 f=f-(sum-1)(sum≥2).

    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN=4e5+5;
    const int mod=1e9+7;
    typedef long long ll;
    //typedef __int128 LL;
    const int inf=0x3f3f3f3f;
    const long long INF=0x3f3f3f3f3f3f3f3f;
    vector<int>g[MAXN];
    int vis[MAXN];
    int len=0;//树的深度,只要顶点到叶子的距离有为奇数的,那么俩叶子节点的边数肯定有为奇数的,同样,如果全为偶数,肯定不存在边数为奇数,就不用计算每两个叶子节点的距离了
    int ansmax,ansmin=1;
    void dfs(int u)
    {
        int sum=0;//同一个节点的叶子节点个数
        for(int i=0;i<g[u].size();i++)
        {
            int v=g[u][i];
            if(vis[v]==1)continue;
            len++;
            vis[v]=1;
            if(g[v].size()==1)
            {
                sum++;
                if(len%2&&len>=3)ansmin=3;
            }
            dfs(v);
            len--;
        }
        if(sum>=2||len==1)
        {
            if(len==1)ansmax=ansmax-sum;
            else ansmax=ansmax-sum+1;
        }
    }
    int main()
    {
        int n;
        scanf("%d",&n);
        int u,v;
        for(int i=1;i<=n-1;i++)
        {
            v,u;
            scanf("%d%d",&v,&u);
            g[v].push_back(u);
            g[u].push_back(v);
        }
        for(int i=1;i<=n;i++)
        {
            if(g[i].size()==1)
            {
                u=i;//以叶子节点作为顶点
                break;
            }
        }
        ansmax=n-1;
        vis[u]=1;
        dfs(u);
        printf("%d %d
    ",ansmin,ansmax);
        return 0;
    }
    View Code
  • 相关阅读:
    带有通配符的字符串匹配算法-C/C++
    二叉树的遍历(一)
    What is "dll"?
    MFC中的CRect(区域)
    枚举顶级窗口函数EnumWindows和它的回调函数的使用!
    一个鼠标指针有关的启发(存在问题,可以参考一下 呵呵)
    9针串口
    About “PostMessage” &"SendMessage"
    Pocket pc模拟器与PC机传输文件的方法
    overlapped I/O的学习笔记
  • 原文地址:https://www.cnblogs.com/MZRONG/p/12690971.html
Copyright © 2011-2022 走看看