zoukankan      html  css  js  c++  java
  • 自建物流的无人机实验(困难)

    题目链接:http://nanti.jisuanke.com/t/440

    假设知道最终答案,那么以某点x为根的点对数公式可以列出,其中Cx表示x为根的子树无人机的个数,xi为x的直接子节点:

    {C_{x}choose {2}} -  sumlimits_{i=1}^n{C_{x_{i}}choose {2}}

    根据公式可以看出几点:

    (1).某个点若满足条件,则只与以该点为根的子树无人机分布情况有关。

    (2).根据(1)进一步分析知,解决某点的分配方案需要递归解决该点的所有子树

    (3).对公式逆向思维,假设点x为根的树分配个数最少为Cx,那么为了满足题意,则应该使上面公式得出的值尽可能大,而Cx假设确定,即被减数固定,那么应使减数尽量小。所有Cxi的和是Cx,固定。那么,Cxi的方差越小则减数越小。

    然后就能做了。

    2遍DFS,第一遍确定以x为根的Cx是多少,用优先队列维护子树的Cxi,每次选取Cxi最小的i,即能保证方差最小。第二遍根据求出的Cx,确定每个点是选取还是不选取……

    #include <queue>
    #include <cstdio>
    #include <cstring>
    
    using namespace std;
    typedef long long  ll;
    
    #define read freopen("in.txt","r",stdin)
    #define N 100020
    struct str
    {
        int n,v;
    }ed[N];
    int head[N],cnt;
    void init()
    {
        memset(head,-1,sizeof(head));
        cnt = 0;
    }
    void add(int u,int v)
    {
        ed[cnt].n = head[u];
        ed[cnt].v = v;
        head[u] = cnt++;
    }
    ll a[N],b[N],c[N];
    bool vis[N];
    bool dfs(int u)
    {
        b[u] = 1, c[u] = 0, vis[u] = false;
        ll t = 0;
        priority_queue< pair<int,int> >q;
        for (int i = head[u]; ~i; i = ed[i].n)
        {
            int v = ed[i].v;
            if(!dfs(v))return false;
            b[u] += b[v];
            c[u] += c[v];
            t -= c[v]*(c[v]-1)/2;
            if (c[v] < b[v])q.push(make_pair(-c[v],v));
        }
        t += c[u]*(c[u]-1)/2;
        q.push(make_pair(0,u));
    
        for (;c[u] <= b[u]; ++c[u])
        {
            if (t >= a[u])return true;
            t -= c[u]*(c[u]-1)/2;
            t += (c[u]+1)*c[u]/2;
            int x = -q.top().first, y = q.top().second;
            q.pop();
            t += x*(x-1)/2;
            t -= (x+1)*x/2;
            if (y == u)
            {
                vis[u] = true;
                continue;
            }
            ++ c[y];
            if (x+1 < b[y])q.push(make_pair(-x-1,y));
        }
        return false;
    }
    void dfs2(int u,ll f)
    {
        for (int i = head[u]; ~i; i = ed[i].n)
            f -= c[ed[i].v];
        if (vis[u])--f;
    
        for (int i = head[u]; ~i; i = ed[i].n)
        {
            int v = ed[i].v;
            ll t = min(f,b[v]-c[v]);
            dfs2(v,t+c[v]);
            f -= t;
            c[u] -= (t+c[v]);
        }
        if (f)vis[u] = true;
    }
    int main()
    {
        //read;
        int n;
        while (~scanf("%d",&n))
        {
            for (int i = 1; i <= n; ++i)
                scanf("%lld",a+i);
            init();
            int u,v;
            for (int i = 1; i < n; ++i)
            {
                scanf("%d%d",&u,&v);
                add(u,v);
            }
            if(!dfs(1))
            {
                puts("-1");
                continue;
            }
            dfs2(1,c[1]);
            int cnt = 0;
            for (int i = 1; i <= n; ++i)
                if(vis[i]) cnt++;
            printf("%d
    ",cnt);
            bool ff = false;
            for (int i = 1; i <= n; ++i)
                if(vis[i])
                {
                    if (ff)printf(" ");
                    else ff = true;
                    printf("%d",i);
                }
            if(cnt)puts("");
        }
        return 0;
    }

    这题告诉我们,学好数学很重要,列出公式就能看穿题目……

  • 相关阅读:
    Jeecms3.x 常用标签使用总结
    MySQL的常用参数设置
    如何让iframe透明
    转载 张子阳 学习记录 c#网络编程
    Automate download of Realtime Trade and MarketDepth stocks demonstration
    c#2.0 锐利体验 视频链接 (李建忠老师主讲)
    转载 张子阳 学习记录 c#网络编程 5
    关于连接 providers 的一些代码 (学习QD)
    转载张子阳 学习记录 c#网络编程 4
    转载 张子阳 学习记录 c#网络编程
  • 原文地址:https://www.cnblogs.com/mcflurry/p/4662221.html
Copyright © 2011-2022 走看看