【2020牛客多校】第三场D-Points Construction Problem——构造

Points Construction Problem

https://ac.nowcoder.com/acm/contest/5668/D

D-Points Construction Problem

思路

第一点:千万不要考虑矩阵,千万不要考虑矩阵,千万不要考虑矩阵。因为完全可以是两个三个矩阵和几条链组成,这实在过于难考虑

这道题最难以考虑的地方就是矩阵的构造。这里给出一个思路去解决这个问题。
当然可能这个方法不是最正确的,但是结果是最优(毕竟AC了)

计算缺失边数

这个应该相对简单,即公式 (n * 4 - m) / 2 的结果

类矩阵结构

这里我们仅考虑非单链的结构,即可以出现矩阵的结构,即 的情况

我们首先给出一个矩阵的核心部分,暂时称其为“核”
核
这个核有一个特性:4个点能够增加4条边,记作:

这是一个矩阵的基础,而且一个矩阵仅需要一个核。

接下来最贪心的方法就是放下这样两个蓝色的点
23
这个结构能够实现用2个点增加3条边,记作:

同样,我们也可以在上面放下这样的结构

23
同样被记作:

值得注意的是:核结构 是所有类矩阵结构的前提,但是由于其产生的连边数量非常少,所以尽可能的减少其使用,即整个图结构仅使用一次 。而 则没有次数限制,可以向上也可以向右

在上图的基础上,我们还可以提出一个结构:
12
这个橙色的点非常的巧妙,其实现了一个点新增了两条边,记作

很明显, 结构是最优的,结构越多则越能用较少的点来实现缺失的边的需求。所以我们需要尽可能的增加 的结构

但是,此结构有数量限制,其数量受到 的数量限制。

再考虑到矩阵的结构能够带来更多的 结构,所以我们选择采用如下的贪心策略

  1. 先放一个的矩阵
  2. 向上/右扩展
  3. 结构填充矩阵
  4. 向右/上扩展
  5. 结构填充矩阵
  6. 重复 直到缺失边全部被满足
  7. 如果使用的点数超出提供的,则无解,否则将多余的点数放在遥远的天边,然后输出

剩余不满足结构

由于上述策略可能会出现遗留下 条缺失边,则我们可以把点放在矩阵的左下角,即图中的×
x
则可以满足一条缺失边或者两条缺失边的要求

AC code

#include <bits/stdc++.h>

using namespace std;

bool flag[60][60];

void print(int n) {
    if (n < 0) {
        cout << "No" << endl;
        return;
    }
    cout << "Yes" << endl;
    while (n--)
        cout << n * 100 << " " << n * 100 << endl;
    for (int i = 0; i < 60; ++i)
        for (int j = 0; j < 60; ++j)
            if (flag[i][j])
                cout << i + 1 << " " << j + 1 << endl;
}

void solve() {
    int T;
    cin >> T;
    for (int ts = 0; ts < T; ++ts) {
        int n, m;
        cin >> n >> m;
        int target = (n * 4 - m) / 2;
        if ((n * 4 - m) & 1) {
            n = -1;
            print(n);
            continue;
        }
        memset(flag, 0, sizeof(flag));

        if (target < 4) {
            int x = 2;
            flag[1][1] = true;
            n--;

            while (target && n >= 0) {
                flag[x][1] = true;
                x++;
                target--;
                n--;
            }
            print(n);
            continue;
        }
        flag[1][1] = flag[1][2] = flag[2][1] = flag[2][2] = true;
        n -= 4;
        target -= 4;

        int l = 3, r = 3;
        while (target > 2) {
            // 右扩展
            flag[1][l] = true;
            flag[2][l] = true;
            l++;
            target -= 3;
            n -= 2;

            int len = 3;
            while (len < r && target > 1) {
                flag[len][l - 1] = true;
                target -= 2;
                n--;
                len++;
            }

            if (target > 2) {
                // 上扩展
                flag[r][1] = true;
                flag[r][2] = true;
                r++;
                target -= 3;
                n -= 2;

                len = 3;
                while (len < l && target > 1) {
                    flag[r - 1][len] = true;
                    target -= 2;
                    n--;
                    len++;
                }
            }
        }

        if (target == 2) {
            n -= 2;
            flag[0][1] = true;
            flag[1][0] = true;
        } else if (target == 1) {
            n -= 1;
            flag[0][1] = true;
        }
        print(n);
    }
}

signed main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
#ifdef ACM_LOCAL
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
    int test_index_for_debug = 1;
    char acm_local_for_debug;
    while (cin >> acm_local_for_debug) {
        if (acm_local_for_debug == '$') exit(0);
        cin.putback(acm_local_for_debug);
        if (test_index_for_debug > 20) {
            throw runtime_error("Check the stdin!!!");
        }
        auto start_clock_for_debug = clock();
        solve();
        auto end_clock_for_debug = clock();
        cout << "Test " << test_index_for_debug << " successful" << endl;
        cerr << "Test " << test_index_for_debug++ << " Run Time: "
             << double(end_clock_for_debug - start_clock_for_debug) / CLOCKS_PER_SEC << "s" << endl;
        cout << "--------------------------------------------------" << endl;
    }
#else
    solve();
#endif
    return 0;
}
全部评论

相关推荐

从输入URL到页面加载发生了什么:总体来说分为以下几个过程:&nbsp;1.DNS解析&nbsp;2.TCP连接&nbsp;3.发送HTTP请求&nbsp;4.服务器处理请求并返回HTTP报文&nbsp;5.浏览器解析渲染页面&nbsp;6.连接结束。简述了一下各个过程的输入输出作用:以下是对从输入&nbsp;URL&nbsp;到页面加载各过程的输入、输出或作用的一句话描述:DNS&nbsp;解析:&nbsp;输入:用户在浏览器地址栏输入的域名(如&nbsp;www.example.com)。输出:对应的&nbsp;IP&nbsp;地址(如&nbsp;192.168.1.1)。作用:将易于记忆的域名转换为计算机能够识别和用于网络通信的&nbsp;IP&nbsp;地址,以便浏览器与目标服务器建立连接。TCP&nbsp;连接:&nbsp;输入:浏览器获得的服务器...
明天不下雨了:参考一下我的说法: 关键要讲出输入网址后涉及的每一个网络协议的工作原理和作用: 涉及到的网络协议: HTTP/HTTPS协议->DNS协议->TCP协议->IP协议->ARP协议 面试参考回答: 第一次访问(本地没有缓存时): 一般我们在浏览器地址栏输入的是一个域名。 浏览器会先解析 URL、解析出域名、资源路径、端口等信息、然后构造 HTTP 请求报文。浏览器新开一个网络线程发起HTTP请求(应用层) 接着进行域名解析、将域名解析为 IP 地址 浏览器会先检查本地缓存(包括浏览器 DNS 缓存、操作系统缓存等)是否已解析过该域名 如果没有、则向本地 DNS 服务器请求解析; 本地服务器查不到会向更上层的 DNS 服务器(根域名服务器->顶级域名服务器->权威域名服务器询问)递归查询 最终返回该域名对应的 IP 地址。(应用层DNS协议)DNS 协议的作用: 将域名转换为 IP 地址。 由于 HTTP 是基于 TCP 传输的、所以在发送 HTTP 请求前、需要进行三次握手、在客户端发送第一次握手的时候、( 浏览器向服务器发送一个SYN(同步)报文、其中包含客户端的初始序列号。TCP头部设置SYN标志位、并指定客户端端口 同时填上目标端口和源端口的信息。源端口是浏览器随机生成的、目标端口要看是 HTTP 还是 HTTPS、如果是 HTTP 默认目标端口是 80、如果是 HTTPS 默认是 443。(传输层) 然后到网络层:涉及到(IP协议) 会将TCP报文封装成IP数据包、添加IP头部,包含源IP地址(浏览器)和目标IP地址(服务器)。IP 协议的作用: 提供无连接的、不可靠的数据包传输服务。 然后到数据链路层、会通过 ARP 协议、获取目标的路由器的 MAC 地址、然后会加上 MAC 头、填上目标 MAC 地址和源 MAC 地址。 然后到物理层之后、直接把数据包、转发给路由器、路由器再通过下一跳、最终找到目标服务器、然后目标服务器收到客户的 SYN 报文后,会响应第二次握手。 当双方都完成三次握手后、如果是 HTTP 协议、客户端就会将 HTTP 请求就会发送给目标服务器。如果是 HTTPS 协议、客户端还要和服务端进行 TLS 四次握手之后、客户端才会将 HTTP 报文发送给目标服务器。 目标服务器收到 HTTP 请求消息后、就返回 HTTP 响应消息、浏览器会对响应消息进行解析渲染、呈现给用户
点赞 评论 收藏
分享
喜欢疯狂星期四的猫头鹰在研究求职打法:短作业优先
点赞 评论 收藏
分享
04-28 19:31
门头沟学院 Java
真烦好烦真烦:可恶的二手车贩子,居然对我们门头沟学院的人这么没礼貌
点赞 评论 收藏
分享
评论
8
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务