题目简述
健佳是一个喜欢做游戏的小男生。当有人问问题时,他更喜欢通过玩游戏的方式作答,而不是直接回答。健佳碰到了他的朋友梅玉,跟她讲了台湾的航空网。在台湾有 $n$ 个城市(编号为 $0, \dots, n - 1$),其中有些城市之间有航线。每个航线连接两个城市,并且是双向的。
梅玉问健佳,是否任意两个城市之间都可以坐飞机互达(直接或间接),健佳不想直接回答,而是要通过做游戏的方式来告诉她。梅玉可以问"城市 $u$ 和 $v$ 之间有直接航线吗?",健佳会立刻直接回答该问题。梅玉会询问每对城市恰好一次,因此总计会有 $r = n(n - 1) /2 $ 个问题。如果由前 $i$($i < r$)个问题的答案可以推断出整个航空网是否连通,也就是说,是否任意一对城市之间都可以坐飞机互达(直接或间接),梅玉就获胜。否则意味着她需要知道全部 $r$ 个回答,此时健佳获胜。
为了让游戏更好玩,他们俩同意,健佳可以不要管台湾的真实航空网,而是可以随着游戏的进展而编造航空网,也就是根据梅玉此前的提问来决定此后如何作答。你的任务是,通过决定健佳如何回答,来帮助他赢得游戏。
任务
请写出一个可以帮助健佳获胜的程序。注意,无论是梅玉还是健佳,都不知道对方的策略。梅玉可以以任意的顺序来询问城市对,而健佳必须在不清楚后面提问的前提下立刻给出回答。你需要实现下面的两个函数:
- initialize(n) —— 我们会先调用你的 initialize 函数。参数 $n$ 是城市数目。
- hasEdge(u, v) —— 接着我们会调用 hasEdge 函数 $r = n(n - 1)/2$ 次。这些调用代表了梅玉的提问,顺序与她提问的次序相同。你必须回答在城市 $v$ 和 $u$ 之间是否有直接航线。具体而言,返回值 $1$ 表示有,$0$ 表示没有。
子任务
每个子任务包含若干个游戏。只有在你的程序帮助健佳赢得了某个子任务中的所有游戏之后,才能得到该子任务的分数。
子任务 | 分值 | $n$ |
---|---|---|
1 | 15 | $n = 4$ |
2 | 27 | $4 \leq n \leq 80$ |
3 | 58 | $4 \leq n \leq 1500$ |
实现细节
本题只支持 C/C++。
你只能提交一个源文件实现上述的函数,其命名与接口需遵循下面的要求。你还要在该文件中包含头文件game.h。
void initialize(int n);
int hasEdge(int u, int v);
评测方式
评测系统将读入如下格式的输入数据:
- 第 $1$ 行:$n$。
- 余下 $r$ 行:每行包含两个整数 $u$ 和 $v$,表示对城市 $u$ 和 $v$ 的提问。
时间限制:$1\texttt{s}$
空间限制:$256\texttt{MB}$
下载
真·水·构造题
一开始的想法是,尽量的使得两个联通块最后才联通,这样就能使得不到最后一步,整张图无法联通
那么,用并查集维护一下,每次\(O(n^2)\)查询一下涉及的两个联通块加入新的边以后是否完整了
完整了,那么要返回两条边联通,否在返回不连通
但这样的话,最后一部分数据是要TLE的
#include "game.h"
#include<cstring>
#include<cstdio>
int fa[2010],a[2010][2010],N;
int Find(int x)
{
return x==fa[x]?x:fa[x]=Find(fa[x]);
}
void initialize(int n) {
N=n;
for (int i=0;i<n;i++)
fa[i]=i;
memset(a,0,sizeof(a));
}
bool check(int x,int y,int n)
{
for (int i=0;i<n;i++)
for (int j=0;j<n;j++)
if (Find(i)==x && Find(j)==y)
if (!a[i][j]) return false;
return true;
}
int hasEdge(int u, int v) {
a[u][v]=a[v][u]=1;
if (check(Find(u),Find(v),N)) {fa[Find(u)]=Find(v);return 1;}
else return 0;
}
然后发现....我可能制杖了啊
直接判断这条边是否是当前点连出的最后一条边即可
因为要保证每一个点都联通的话,至少存在一条边连入图中
这样的话,如果压个行,一行就解决了啊
#include "game.h"
#include<cstdio>
#include<cstring>
#include<iostream>
int a[2010],N;
void initialize(int n) {
memset(a,0,sizeof(a));N=n;
}
int hasEdge(int x, int y) {
if (x<y) std::swap(x,y);
a[x]++;
if (a[x]==x) return 1;else return 0;
}