5-6 笛卡尔树 (25分)

本文介绍了一种用于判断给定二叉树是否为笛卡尔树的算法。笛卡尔树需同时满足二叉搜索树和最小堆的性质。通过中序遍历检查K1值的顺序及比较各节点K2值来完成验证。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

5-6 笛卡尔树   (25分)

笛卡尔树是一种特殊的二叉树,其结点包含两个关键字K1和K2。首先笛卡尔树是关于K1的二叉搜索树,即结点左子树的所有K1值都比该结点的K1值小,右子树则大。其次所有结点的K2关键字满足优先队列(不妨设为最小堆)的顺序要求,即该结点的K2值比其子树中所有结点的K2值小。给定一棵二叉树,请判断该树是否笛卡尔树。

输入格式:

输入首先给出正整数N(\le1000),为树中结点的个数。随后N行,每行给出一个结点的信息,包括:结点的K1值、K2值、左孩子结点编号、右孩子结点编号。设结点从0~(N-1)顺序编号。若某结点不存在孩子结点,则该位置给出-11

输出格式:

输出YES如果该树是一棵笛卡尔树;否则输出NO

输入样例1:

6
8 27 5 1
9 40 -1 -1
10 20 0 3
12 21 -1 4
15 22 -1 -1
5 35 -1 -1

输出样例1:

YES

输入样例2:

6
8 27 5 1
9 40 -1 -1
10 20 0 3
12 11 -1 4
15 22 -1 -1
50 35 -1 -1

输出样例2:

NO


思路:

BST的满足键值判断,要依据中序遍历是否有序。。。完了,明天期中要炸,233333

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

int pre[1010];
struct BST{
    int left;
    int right;
    int k1;
    int k2;
}q[1010];

int flag;

void Judge(int num)
{
    int left,right;
    if(!flag)
        return;
    if(q[num].left!=-1)
    {
        left=q[num].left;
        if(q[left].k2<q[num].k2)
        {
            flag=0;
            return;
        }
        Judge(left);
    }
    if(q[num].right!=-1)
    {
        right=q[num].right;
        if(q[right].k2<q[num].k2)
        {
            flag=0;
            return;
        }
        Judge(right);
    }
}

int bb[1010],aa[1010];
int num_b;
void inorder(int num)
{
    if(num==-1)
        return;
    inorder(q[num].left);
    aa[num_b]=bb[num_b]=q[num].k1;
    num_b++;
    inorder(q[num].right);
}

int main()
{
    int n,k1,k2,left,right;
    memset(pre,0,sizeof(pre));
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        scanf("%d%d%d%d",&k1,&k2,&left,&right);
        q[i].k1=k1;
        q[i].k2=k2;
        q[i].left=left;
        q[i].right=right;
        if(left!=-1)
            pre[left]++;
        if(right!=-1)
            pre[right]++;
    }
    int root;
    for(int i=0;i<n;i++)
    {
        if(!pre[i])
        {
            root=i;
            break;
        }
    }
    flag=1;
    Judge(root);
    num_b=0;
    inorder(root);
    for(int i=0;i<num_b;i++)
    {
        for(int j=i+1;j<num_b;j++)
        {
            if(aa[j]<aa[j-1])
            {
                int temp=aa[j-1];
                aa[j-1]=aa[j];
                aa[j]=temp;
            }
        }
    }
    for(int i=0;i<num_b;i++)
    {
        if(aa[i]!=bb[i])
        {
            flag=0;
            break;
        }
    }
    if(flag)
        puts("YES");
    else
        puts("NO");

    return 0;
}







#include <Windows.h> #include <string> #include <vector> #include <sstream> // 定义控件ID #define ID_EDIT_AX 101 #define ID_EDIT_AY 102 #define ID_EDIT_BX 103 #define ID_EDIT_BY 104 #define ID_BUTTON_DRAW 105 #define ID_BUTTON_CLEAR 106 // 存储点坐标的结构体 struct Point { float x = 0.0f; float y = 0.0f; bool valid = false; }; // 全局变量存储点A和B Point g_pointA; Point g_pointB; // 窗口过程函数 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps); // 获取客户区尺寸 RECT rect; GetClientRect(hWnd, &rect); int width = rect.right - rect.left; int height = rect.bottom - rect.top; // 设置坐标系原点在左下角 int originX = 50; // 左边距 int originY = height - 50; // 下边距 // 创建白色画笔用于坐标轴 HPEN hAxisPen = CreatePen(PS_SOLID, 2, RGB(255, 255, 255)); HPEN hOldPen = (HPEN)SelectObject(hdc, hAxisPen); // 绘制X轴(带箭头) MoveToEx(hdc, originX, originY, NULL); LineTo(hdc, width - 20, originY); // X轴主线段 // X轴箭头 LineTo(hdc, width - 30, originY - 5); MoveToEx(hdc, width - 20, originY, NULL); LineTo(hdc, width - 30, originY + 5); // 绘制Y轴(带箭头) MoveToEx(hdc, originX, originY, NULL); LineTo(hdc, originX, 20); // Y轴主线段 // Y轴箭头 LineTo(hdc, originX - 5, 30); MoveToEx(hdc, originX, 20, NULL); LineTo(hdc, originX + 5, 30); // 创建虚线画笔用于网格线 HPEN hGridPen = CreatePen(PS_DOT, 1, RGB(100, 100, 100)); SelectObject(hdc, hGridPen); // 绘制网格线(每50像素一条) for (int x = originX + 50; x < width - 20; x += 50) { MoveToEx(hdc, x, originY, NULL); LineTo(hdc, x, 20); } for (int y = originY - 50; y > 20; y -= 50) { MoveToEx(hdc, originX, y, NULL); LineTo(hdc, width - 20, y); } // 恢复原始画笔 SelectObject(hdc, hOldPen); DeleteObject(hAxisPen); DeleteObject(hGridPen); // 设置文本颜色为白色 SetTextColor(hdc, RGB(255, 255, 255)); SetBkColor(hdc, RGB(0, 0, 0)); // 黑色背景 // 绘制刻度标记 for (int i = 1; i <= 10; i++) { int xPos = originX + i * 50; int yPos = originY - i * 50; // X轴刻度 MoveToEx(hdc, xPos, originY - 5, NULL); LineTo(hdc, xPos, originY + 5); // Y轴刻度 MoveToEx(hdc, originX - 5, yPos, NULL); LineTo(hdc, originX + 5, yPos); // 绘制刻度值 std::wstring label = std::to_wstring(i); TextOut(hdc, xPos - 5, originY + 10, label.c_str(), label.length()); TextOut(hdc, originX - 25, yPos - 8, label.c_str(), label.length()); } // 绘制坐标轴标签 TextOut(hdc, width - 15, originY - 15, L"X", 1); TextOut(hdc, originX - 15, 15, L"Y", 1); TextOut(hdc, originX - 10, originY + 10, L"0", 1); // 如果点A和点B有效,绘制它们并连接 if (g_pointA.valid && g_pointB.valid) { // 转换为屏幕坐标 int screenAx = originX + static_cast<int>(g_pointA.x * 50); int screenAy = originY - static_cast<int>(g_pointA.y * 50); int screenBx = originX + static_cast<int>(g_pointB.x * 50); int screenBy = originY - static_cast<int>(g_pointB.y * 50); // 创建红色画笔用于直线 HPEN hLinePen = CreatePen(PS_SOLID, 2, RGB(255, 0, 0)); SelectObject(hdc, hLinePen); // 绘制直线 MoveToEx(hdc, screenAx, screenAy, NULL); LineTo(hdc, screenBx, screenBy); // 创建红色实心画笔用于点 HBRUSH hRedBrush = CreateSolidBrush(RGB(255, 0, 0)); HBRUSH hOldBrush = (HBRUSH)SelectObject(hdc, hRedBrush); // 绘制点A Ellipse(hdc, screenAx - 5, screenAy - 5, screenAx + 5, screenAy + 5); TextOut(hdc, screenAx + 10, screenAy - 10, L"A", 1); // 绘制点B Ellipse(hdc, screenBx - 5, screenBy - 5, screenBx + 5, screenBy + 5); TextOut(hdc, screenBx + 10, screenBy - 10, L"B", 1); // 计算并显示距离 float distance = sqrtf(powf(g_pointB.x - g_pointA.x, 2) + powf(g_pointB.y - g_pointA.y, 2)); std::wstring distText = L"距离: " + std::to_wstring(distance).substr(0, 4); TextOut(hdc, width - 150, 30, distText.c_str(), distText.length()); // 恢复并删除对象 SelectObject(hdc, hOldBrush); DeleteObject(hLinePen); DeleteObject(hRedBrush); } EndPaint(hWnd, &ps); break; } case WM_CREATE: { // 创建输入框和标签 CreateWindow(L"STATIC", L"A点 X:", WS_CHILD | WS_VISIBLE | SS_CENTER, 10, 10, 50, 20, hWnd, NULL, NULL, NULL); CreateWindow(L"EDIT", L"", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_NUMBER, 65, 10, 50, 20, hWnd, (HMENU)ID_EDIT_AX, NULL, NULL); CreateWindow(L"STATIC", L"Y:", WS_CHILD | WS_VISIBLE | SS_CENTER, 120, 10, 20, 20, hWnd, NULL, NULL, NULL); CreateWindow(L"EDIT", L"", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_NUMBER, 145, 10, 50, 20, hWnd, (HMENU)ID_EDIT_AY, NULL, NULL); CreateWindow(L"STATIC", L"B点 X:", WS_CHILD | WS_VISIBLE | SS_CENTER, 10, 40, 50, 20, hWnd, NULL, NULL, NULL); CreateWindow(L"EDIT", L"", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_NUMBER, 65, 40, 50, 20, hWnd, (HMENU)ID_EDIT_BX, NULL, NULL); CreateWindow(L"STATIC", L"Y:", WS_CHILD | WS_VISIBLE | SS_CENTER, 120, 40, 20, 20, hWnd, NULL, NULL, NULL); CreateWindow(L"EDIT", L"", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_NUMBER, 145, 40, 50, 20, hWnd, (HMENU)ID_EDIT_BY, NULL, NULL); // 创建按钮 CreateWindow(L"BUTTON", L"绘制", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 210, 10, 80, 25, hWnd, (HMENU)ID_BUTTON_DRAW, NULL, NULL); CreateWindow(L"BUTTON", L"清除", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 210, 40, 80, 25, hWnd, (HMENU)ID_BUTTON_CLEAR, NULL, NULL); // 设置默认值 SetDlgItemText(hWnd, ID_EDIT_AX, L"2"); SetDlgItemText(hWnd, ID_EDIT_AY, L"3"); SetDlgItemText(hWnd, ID_EDIT_BX, L"7"); SetDlgItemText(hWnd, ID_EDIT_BY, L"8"); break; } case WM_COMMAND: { int wmId = LOWORD(wParam); if (wmId == ID_BUTTON_DRAW) { // 获取输入的坐标值 wchar_t text[32]; GetDlgItemText(hWnd, ID_EDIT_AX, text, 32); g_pointA.x = _wtof(text); GetDlgItemText(hWnd, ID_EDIT_AY, text, 32); g_pointA.y = _wtof(text); GetDlgItemText(hWnd, ID_EDIT_BX, text, 32); g_pointB.x = _wtof(text); GetDlgItemText(hWnd, ID_EDIT_BY, text, 32); g_pointB.y = _wtof(text); // 验证坐标是否在有效范围内(0-10) g_pointA.valid = (g_pointA.x >= 0 && g_pointA.x <= 10 && g_pointA.y >= 0 && g_pointA.y <= 10); g_pointB.valid = (g_pointB.x >= 0 && g_pointB.x <= 10 && g_pointB.y >= 0 && g_pointB.y <= 10); // 重绘窗口 InvalidateRect(hWnd, NULL, TRUE); } else if (wmId == ID_BUTTON_CLEAR) { // 清除点 g_pointA.valid = false; g_pointB.valid = false; // 重绘窗口 InvalidateRect(hWnd, NULL, TRUE); } break; } case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } // 应用程序入口点 int WINAPI wWinMain( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) { // 1. 注册窗口类 const wchar_t CLASS_NAME[] = L"CartesianWindowClass"; WNDCLASSEXW wcex = { sizeof(WNDCLASSEX) }; wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.hInstance = hInstance; wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); wcex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); // 黑色背景 wcex.lpszClassName = CLASS_NAME; if (!RegisterClassExW(&wcex)) { MessageBox(NULL, L"窗口类注册失败!", L"错误", MB_ICONERROR); return 1; } // 2. 计算窗口尺寸(包含边框和标题栏) int clientWidth = 600; int clientHeight = 600; RECT rect = { 0, 0, clientWidth, clientHeight }; AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE); int windowWidth = rect.right - rect.left; int windowHeight = rect.bottom - rect.top; // 3. 计算居中位置 int screenWidth = GetSystemMetrics(SM_CXSCREEN); int screenHeight = GetSystemMetrics(SM_CYSCREEN); int posX = (screenWidth - windowWidth) / 2; int posY = (screenHeight - windowHeight) / 2; // 4. 创建窗口 HWND hWnd = CreateWindowExW( 0, // 无扩展样式 CLASS_NAME, L"笛卡尔坐标系 - 绘制点A和点B", WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX, // 禁用调整大小和最大化 posX, posY, // 位置 windowWidth, // 宽度 windowHeight, // 高度 nullptr, nullptr, hInstance, nullptr); if (!hWnd) { MessageBox(NULL, L"窗口创建失败!", L"错误", MB_ICONERROR); return 1; } // 5. 显示窗口 ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); // 6. 消息循环 MSG msg; while (GetMessage(&msg, nullptr, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam; } 将以上代码接入我发的代码中,并给我全部无删减的完整代码
最新发布
07-22
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值