Palace(拓扑排序+图型dp)

有用点个赞呗@_@

题目描述

To celebrate the victory of the war, Pisces has decided to build a splendid palace. The craftsmen has brought back n kinds of cube materials from the dwarf kingdom. The length, width, and height of each material are a, b and c respectively. To make the palace magnificent, the craftsmen have to stack these materials together. Material i can be stacked on material j if and only if a i < a j ⋂ b i < b j a_i<a_j⋂b_i<b_j ai<ajbi<bj, or a i < b j ⋂ b i < a j a_i<b_j⋂b_i<a_j ai<bjbi<aj. Pisces wants to know how high these materials can stack at most
题意简述:
有n个长方体,a,b,c是长,宽,高,
a i < a j ⋂ b i < b j a_i<a_j⋂b_i<b_j ai<ajbi<bj, 或 a i < b j ⋂ b i < a j a_i<b_j⋂b_i<a_j ai<bjbi<aj,则说明i可以放在j上
求可以达到的最大高度。

样例输入

The first line contains an integer T (1≤T≤10)(1≤T≤10), which denotes the number of test cases.
For each of the test cases, the first line contains an integer n(1≤n≤2∗103)(1≤n≤2∗103), which represents the number of materials. Each of the next n lines contains 3 integers a, b and c (1≤a,b,c≤1000)(1≤a,b,c≤1000), which represents the size of a material.
1
3
2 3 5
4 3 4
3 3 3

样例输出

For each test case, print the maximum height.
9

算法简述

暴力建图,用拓扑排序的方法以一个拓扑序列的次序对每个节点dp即可

细节

如何建图?

若i可以放在j上,那么加一条i到j的有向边,这里我用的是链式前向*存法

如何dp?

dp[i]代表以i为最上面的方块为i能达到的最高高度
对于正在处理的节点:
枚举其出度边,边终点为j,则更新dp[j]
dp[j]=max(dp[j],dp[i]+j.c);

代码

#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <stdio.h>
#include <string.h>
using namespace std;
#pragma warning(disable:4996)
#define MAX(a,b) (a>b?a:b)
#define MIN(a,b) (a<b?a:b)
const int maxn = 2005, maxm = 1999005;
int H[maxn], NXT[maxm],E[maxm], eSize;
void add(int from ,int to)
{
    eSize++;
    E[eSize] = to;
    NXT[eSize] = H[from];
    H[from] = eSize;
}
int n, T;
struct dat
{
    int a, b, c;
};
dat v[maxn];
int tag[maxn];
int dp[maxn];
int indegree[maxn];
int main()
{
    scanf("%d", &T);
    while (T--)
    {
        memset(dp, 0, sizeof(dp));
        memset(H, 0, sizeof(H));
        memset(NXT, 0, sizeof(NXT));
        memset(indegree, 0, sizeof(indegree));
        eSize = 0;
        scanf("%d", &n);
        for (int i = 1 ;i <= n; i++)
        {
            scanf("%d%d%d", &v[i].a, &v[i].b, &v[i].c);
        }
        for (int i = 1; i <= n; i++)
        {
            for (int j = i + 1; j <= n; j++)
            {
                if (MAX(v[i].a,v[i].b) > MAX(v[j].a,v[j].b) && MIN(v[i].a,v[i].b) > MIN(v[j].a, v[j].b))
                {
                    add(i, j);
                    indegree[j]++;
                }
                if (MAX(v[i].a, v[i].b) < MAX(v[j].a, v[j].b) && MIN(v[i].a, v[i].b) < MIN(v[j].a, v[j].b))
                {
                    add(j, i);
                    indegree[i]++;
                }
            }
        }
        queue<int> Q;
        for (int i = 1; i <= n; i++)
        {
            if (!indegree[i])
            {
                Q.push(i);
            }
        }
        while (!Q.empty())
        {
            int x = Q.front(); Q.pop();
            dp[x] = MAX(dp[x], v[x].c);
            for (int i = H[x]; i; i = NXT[i])
            {
                indegree[E[i]]--;
                dp[E[i]] = MAX(dp[E[i]], dp[x] + v[E[i]].c);
                if (!indegree[E[i]])
                {
                    Q.push(E[i]);
                }
            }
        }
        int ans = 0;
        for (int i = 1; i <= n; i++)
        {
            ans = MAX(ans, dp[i]);
        }
        printf("%d\n", ans);
    }
    
}

扩展

任意面可以做底的情况

#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <stdio.h>
#include <string.h>
using namespace std;
#pragma warning(disable:4996)
#define MAX(a,b) (a>b?a:b)
#define MIN(a,b) (a<b?a:b)
const int maxn = 2005, maxm = 1999005;
struct edg
{
    int to, flg1, flg2;
};
edg E[maxm];
int H[maxn], NXT[maxm], eSize;
void add(int from ,int to,int flg1,int flg2)
{
    eSize++;
    E[eSize] = { to,flg1,flg2 };
    NXT[eSize] = H[from];
    H[from] = eSize;
}
int n, T;
struct dat
{
    int a, b, c;
};
dat v[maxn];
int tag[maxn];
int dp[maxn][4];
int indegree[maxn];
inline bool judge(int x, int y, int flg1, int flg2)
{
    int xmin;
    int xmax;
    if (flg1 == 1)
    {
        xmin = MIN(v[x].a, v[x].b);
        xmax = MAX(v[x].a, v[x].b);
    }
    if (flg1 == 2)
    {
        xmin = MIN(v[x].b, v[x].c);
        xmax = MAX(v[x].b, v[x].c);
    }
    else if (flg1 == 3)
    {
        xmin = MIN(v[x].a, v[x].c);
        xmax = MAX(v[x].a, v[x].c);
    }
    int ymin;
    int ymax;
    if (flg2 == 1)
    {
        ymin = MIN(v[y].a, v[y].b);
        ymax = MAX(v[y].a, v[y].b);  
    }
    if (flg2 == 2)
    {
        ymin = MIN(v[y].b, v[y].c);
        ymax = MAX(v[y].b, v[y].c);
    }
    else if (flg2 == 3)
    {
        ymin = MIN(v[y].a, v[y].c);
        ymax = MAX(v[y].a, v[y].c);
    }
    if (ymin < xmin && ymax < xmax)return 1;
    return 0;
}
int main()
{
    scanf("%d", &T);
    while (T--)
    {
        memset(dp, 0, sizeof(dp));
        memset(H, 0, sizeof(H));
        memset(NXT, 0, sizeof(NXT));
        memset(indegree, 0, sizeof(indegree));
        eSize = 0;
        scanf("%d", &n);
        for (int i = 1 ;i <= n; i++)
        {
            scanf("%d%d%d", &v[i].a, &v[i].b, &v[i].c);
        }
        for (int i = 1; i <= n; i++)
        {
            for (int j = i + 1; j <= n; j++)
            {
                for (int flg1 = 1; flg1 <= 3; flg1++)
                {
                    for (int flg2 = 1; flg2 <= 3; flg2++)
                    {
                        if (judge(i, j, flg1, flg2))
                        {
                            indegree[j]++;
                            add(i, j, flg1, flg2);
                        }
                        if (judge(j, i, flg1, flg2))
                        {
                            indegree[i]++;
                            add(j, i, flg1, flg2);
                        }
                    }
                }
            }
        }
        queue<int> Q;
        for (int i = 1; i <= n; i++)
        {
            if (!indegree[i])
            {
                Q.push(i);
            }
        }
        while (!Q.empty())
        {
            int x = Q.front(); Q.pop();
            dp[x][1] = MAX(dp[x][1], v[x].c);
            dp[x][2] = MAX(dp[x][2], v[x].a);
            dp[x][3] = MAX(dp[x][3], v[x].b);
            for (int i = H[x]; i; i = NXT[i])
            {
                indegree[E[i].to]--;
                if (E[i].flg2 == 1)
                {
                    dp[E[i].to][1] = MAX(dp[E[i].to][E[i].flg2], dp[x][E[i].flg1] + v[E[i].to].c);
                }
                else if (E[i].flg2 == 2)
                {
                    dp[E[i].to][2] = MAX(dp[E[i].to][E[i].flg2], dp[x][E[i].flg1] + v[E[i].to].a);
                }
                else if (E[i].flg2 == 3)
                {
                    dp[E[i].to][3] = MAX(dp[E[i].to][E[i].flg2], dp[x][E[i].flg1] + v[E[i].to].b);
                }
                if (!indegree[E[i].to])
                {
                    Q.push(E[i].to);
                }
            }
        }
        int ans = 0;
        for (int i = 1; i <= n; i++)
        {
            ans = MAX(ans, MAX(dp[i][1], max(dp[i][2], dp[i][3])));
        }
        printf("%d\n", ans);
    }
    
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值