poj-3140

22 篇文章 0 订阅
//10344K    391MS   C++
#include <cstdio>
#include <cstring>
#include <cmath>

const long long MAX = 100005;

long long adjacentListHead[MAX];

long long studentTotalSum;

struct Node{
    long long studentNum;
};

long long Idx;

struct ConnectedNode{
    int curNodeId;
    int nextNodePos;
};

typedef struct ConnectedNode ConnectedNode;

ConnectedNode adjacentNodes[1000005];

typedef struct Node Node;

Node nodes[MAX];

long long DP[MAX];

long long uNum;
long long connectionNum;

long long minDiffer = -1;

inline long long MIN(long long A, long long B) {
    return A < B ? A: B;
}

void addInAdjacentList(int nodeId, int adjacentNodeId) {
    Idx++;
    adjacentNodes[Idx].curNodeId = adjacentNodeId;
    adjacentNodes[Idx].nextNodePos = adjacentListHead[nodeId];
    adjacentListHead[nodeId] = Idx;
}

inline long long ABS(long long A) {
    return A > 0? A: -A;
}

void dfs(long long curNodeId, long long prevNodeId) {
    // visited[curNodeId] = 1;
    long long adjacentNodePos = adjacentListHead[curNodeId];
    long long adjacentNodeId = adjacentNodes[adjacentNodePos].curNodeId;

    long long adjacentNum = 0;

    while(adjacentNodeId) {
        // prlong longf("A adjacentNodeId: %d curNodeId: %d prevNodeId: %d\n", adjacentNodeId, curNodeId, prevNodeId);
        if (adjacentNodeId != prevNodeId) {
            dfs(adjacentNodeId, curNodeId);
            adjacentNum++;
            DP[curNodeId] += DP[adjacentNodeId];
        }
        adjacentNodePos = adjacentNodes[adjacentNodePos].nextNodePos;
        adjacentNodeId = adjacentNodes[adjacentNodePos].curNodeId;
    }
    DP[curNodeId] += nodes[curNodeId].studentNum;
    // prlong longf("%lld %d\n", DP[curNodeId], curNodeId);
    if (minDiffer == -1) {
        minDiffer = ABS(studentTotalSum - 2*DP[curNodeId]);
    } else {
         minDiffer = MIN(minDiffer, ABS(studentTotalSum - 2*DP[curNodeId]));
    }
}

long long caseId = 1;
int main() {
    while(scanf("%lld %lld", &uNum, &connectionNum) != EOF) {
        if (!uNum && !connectionNum) {
            return 0;
        }
        Idx = 0;
        studentTotalSum = 0;
        minDiffer = -1;
        memset(DP, 0, sizeof(DP));
        // memset(visited, 0, sizeof(visited));
        memset(adjacentListHead, 0, sizeof(adjacentListHead));
        memset(adjacentNodes, 0, sizeof(adjacentNodes));
        for (long long i = 1; i <= uNum; i++) {
            scanf("%lld", &(nodes[i].studentNum));
            studentTotalSum += nodes[i].studentNum;
        }
        for (long long i = 1; i <= connectionNum; i++) {
            int A, B;
            scanf("%d %d", &A, &B);
            addInAdjacentList(A, B);
            addInAdjacentList(B, A);
        }
        dfs(1, -1);
        printf("Case %lld: %lld\n", caseId, minDiffer);
        caseId++;
    }
}

水题,虽然挂着树状DP的名头,不过是非常简单的运用,倒是因为数据值太大引起了不少RE 和 WA。

题目要求的其实说白了就是,给你一个无根树,然后选择树种中的一条边断开,使得形成的两个子树的权值和的差的绝对值最小。

因为是无根树,所以完全可以任选一个点作为根,而因为题目的输入没有给出两个点的父子关系,并且树的节点非常多,因此在保存该树的时候,要用图的邻接表来表示(好久没用,邻接表的预分配数组开小了,RE了一次),在题目输入的时候,就先累加得到整个树的权值和S, 然后,就是选择一个点作为root(直接选了1),

那么下面就是DP了,DP[i]表示以i为根的子树的权值和,那么很简单的,DP[i] = SUM{DP[i的子节点]}, 注意,因为用的是邻接表表示的树,因此,实际的遍历点i的所有子节点,是通过遍历与i邻接的所有节点实现的,但是在这些邻接的点中,会有一个点其实是i的父节点,这个要区分开,可以在dfs()中多加一个参数P,表示此次dfs的节点i,其父节点是P,这样在遍历i的邻接点时,可以直接将p跳过。

每次得到一个子树的权值和时(即DP[i]),就算一个 abs(S - 2*DP[i])(就是以i为根的子树权值和 与 剩下的点组成的子树的权值和的差的绝对值), 在每次的dfs中,保存最小的abs(S - 2*DP[i]);

最后输出该最小值即可。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值