zoukankan      html  css  js  c++  java
  • Codeforces 1514E Baby Ehab's Hyper Apartment

    官方题解的操作好炫酷啊……

    因为我们能得知的关于边的信息非常有限,所以考虑求出一条「通用」的路径,使得仅通过这些极少的路径就可以完成整张图的连通性的判断。

    下面记题目中给出的两种询问分别为 $ ext{OneEdge}(u, v)$ 和 $ ext{ManyEdges}(u, S)$。

    自然的,我们将目光投向这张竞赛图的哈密顿路径上。

    考虑归并。比如我们现在在找 $[l, r]$ 这些点的哈密顿路径,那么可以分为两个部分 $[l, mid]$ 和 $[mid +1,r]$,递归求解这两部分的哈密顿路径。

    比如 $[l, mid]$ 的哈密顿路径的起点是 $u$,$[mid+1, r]$ 的哈密顿路径的起点是 $v$,那么我们调用 $ ext{OneEdge}(u, v)$,如果边是 $u o v$ 的,那么我们就把 $u$ 放在 $[l, r]$ 的哈密顿路径的第一个,否则把 $v$ 放在第一个。

    上面这么做为什么可行呢?

    比如边是 $u o v$ 的,那么当把 $u$ 放在第一位后,无论下一位是 $v$ 还是 $[l, mid]$ 中 $u$ 的后继,$u$ 都有一条直接连向后面的边,所以哈密顿路径的性质不会被破坏。

    第一位确定以后,我们再继续按照上面的方法去确定第二位、第三位……即可。这个过程本质上就是对两个有序数组的归并。

    当然,其实完全可以不用手写这个归并过程,我们可以调用 STL 的 stable_sort,而 $ ext{OneEdge}$ 恰好就是 Compare 函数!

    也就是说,我们先构造一个数组 $path_i = i$,接下来调用 stable_sort(path + 1, path + n + 1, OneEdge),得到的 $path_1 o path_2 o cdots o path_n$ 就是图中的一条哈密顿路径了。

    上述调用 $ ext{OneEdge}$ 的次数约 $n log n$。

    求出哈密顿路径后,显然所有 $path_i o path_j (i < j)$ 的边就没有意义了,故只需要考虑反向边

    于是我们逆序遍历 $path$ 数组,同时维护一下当前通过反向边最远能追溯到哪里,其实也就是维护一个指针 $p$,只要 $ ext{ManyEdges}(path_{now}, {path_1, path_2, cdots, path_p}) = 1$,就说明至少可以追溯到前 $p$ 位。

    因为 $now$ 和 $p$ 都是单调下降的,所以上述过程是线性的,调用 $ ext{ManyEdges}$ 的次数约为 $2n$。

    于是这个问题就很好地得到了解决,代码非常短。

    #include <bits/stdc++.h>
    using namespace std;
    int n, t, ret;
    bool ans[105][105];
    vector<int> path;
    inline bool ManyEdges(const int &x, int len) // len 表示询问的 S 是 path[0] ~ path[len]
    {
    	if(len < 0) return false;
    	cout << "2 " << x << ' ' << len + 1 << ' ';
    	for(unsigned i = 0; i <= len; i++) cout << path[i] << ' ';
    	cout << endl;
    	cin >> ret;
    	return ret;
    }
    inline bool OneEdge(const int &a, const int &b)
    {
    	cout << "1 " << a << ' ' << b << endl;
    	cin >> ret;
    	return ret;
    }
    int main()
    {
    	ios::sync_with_stdio(false);
    	cin >> t;
    	while(t--)
    	{
    		cin >> n;
    		memset(ans, true, sizeof(ans));
    		path.clear();
    		for(int i = 0; i < n; i++) path.push_back(i);
    		stable_sort(path.begin(), path.end(), OneEdge);
    		int far = n - 2;
    		for(int i = n - 1; ~i; i--)
    		{
    			if(far == i)
    			{
    				for(int j = 0; j <= i; j++) for(int k = i + 1; k < n; k++) ans[path[k]][path[j]] = false;
    				far--;
    			}
    			while(ManyEdges(path[i], far)) far--;
    		}
    		cout << "3
    ";
    		for(int i = 0; i < n; i++, cout << endl) for(int j = 0; j < n; j++) cout << ans[i][j];
    		cin >> n;
    	}
    }
  • 相关阅读:
    华为徐直军第一次非主场演讲,信息量很大
    智慧城市行业领军企业一览表
    【Python】+Django框架使用
    【Python】+pip超时
    【Python】+web应用开发/界面/Django/Flask
    【Java】+【JSON】+对比两个json对象是否完全一样
    【数据库】+多表查询
    【Java】+MD5生成
    【Java】+操作csv文件
    【Java】+反射1+获取属性/成员变量 的名称及类型
  • 原文地址:https://www.cnblogs.com/syksykCCC/p/CF1514E.html
Copyright © 2011-2022 走看看