Codeforces Round #158 (Div. 2)D. Black and White Tree(搜索 + 思维)

题目链接

http://codeforces.com/contest/260/problem/D

题目大意

给你一棵树(注意不要出现环)的所有节点, 节点分为黑、白两类,只有不同颜色的节点才能相连, 每个节点还有一个值, 该值表示该点所连边的权值之和, 最后让你输出每条边所连的两个节点以及其权值(题目为特判)

思路

该题几乎没有用到算法,但十分考验思维
首先sum(edge) = sum(node)
由于只有不同颜色的node才能相连, 所以sum(white) = sum(black)

由这两个式子我们可以得出这么一个结论:从一个节点出发, 取另一种颜色的另一个节点, 我们把较小的值作为该边的权值,那么较大的就要减去这个权值, 再用已经减过的值继续递归地找另一种颜色的节点, 这样一定可以组成一张符合题意的树, 如果还有节点没有使用,那么该节点的值一定为0, 否则就无法加入树中

有很多题解都是排序后贪心找, 其实不用排序, 直接dfs就好了

代码

#include<bits/stdc++.h>
using namespace std;

const int M = 1e5 + 5;

struct node
{
    int id, val;
    bool operator < (node & x)
    {
        return val < x.val;
    }
};
queue<node>b;
queue<node>w;

struct edg
{
    int l, r, val;
};
vector<edg>ans;

void dfs(node v, bool c)
{
    if(c)
    {
        while(!b.empty())
        {
            node tmb = b.front();
            b.pop();
            edg tmp;
            if(tmb.val >= v.val)
            {
                tmp.l = v.id;
                tmp.r = tmb.id;
                tmp.val = v.val;
                ans.push_back(tmp);
                tmb.val -= v.val;
                dfs(tmb, 0);
                return ;
            }
            tmp.l = tmb.id;
            tmp.r = v.id;
            tmp.val = tmb.val;
            ans.push_back(tmp);
            v.val -= tmb.val;
        }

    }
    else
    {
        while(!w.empty())
        {
            node tmw = w.front();
            w.pop();
            edg tmp;
            if(tmw.val > v.val)
            {
                tmp.l = v.id;
                tmp.r = tmw.id;
                tmp.val = v.val;
                ans.push_back(tmp);
                tmw.val -= v.val;
                dfs(tmw, 1);
                return ;
            }
            tmp.l = tmw.id;
            tmp.r = v.id;
            tmp.val = tmw.val;              
            ans.push_back(tmp);
            v.val -= tmw.val;
        }
    }
}

int main()
{
    int n;
    scanf("%d", &n);
    int tb = 0, tw = 0;
    for(int i=1; i<=n; ++i)
    {
        int c, v;
        scanf("%d%d", &c, &v);
        if(c)
        {
            node tmp;
            tmp.id = i;
            tmp.val = v;
            b.push(tmp);
        }
        else
        {
            node tmp;
            tmp.id = i;
            tmp.val = v;
            w.push(tmp);
        }
    }
    int rw = w.front().id, rb = b.front().id;
    node temp = b.front();
    b.pop();
    dfs(temp, 0);
    while(w.size())   //注意最后可能还有节点没有用完,这些没用完的节点的值一定是0,否则那两个式子就不成立了
    {
        node tmw = w.front();
        w.pop();
        edg tmp;
        tmp.l = tmw.id;
        tmp.r = rb;
        tmp.val = 0;
        ans.push_back(tmp);
    }
    while(b.size())
    {
        node tmb = b.front();
        b.pop();
        edg tmp;
        tmp.l = tmb.id;
        tmp.r = rw;
        tmp.val = 0;
        ans.push_back(tmp);
    }
    int len = ans.size();
    for(int i=0; i<len; ++i)
    {
        printf("%d %d %d\n", ans[i].l, ans[i].r, ans[i].val);
    }
    return 0;
}
发布了54 篇原创文章 · 获赞 13 · 访问量 1万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章