思路:
我的傻逼做法:
首先一个简单的性质是如果你知道一张完全图的连边情况你可以推测出其连通性。
我们考虑怎样才能满足题目条件,通过枚举最后一步我们发现如果对于一条边
(u,v)
,在询问之前你就可以推测出其联通性,那么一定无法获胜。
所以我们对每个点维护一个并查集,那么对于当前处于两个不同并查集的
(u,v)
,如果两个并查集中之间的点还有边未连,那么
(u,v)
一定不能联通,但如果都询问了都不连通那会导致对手很容易通过某种策略来判断整个图是不连通的,所以我们就在两个并查集连最后一条边的时候把它们合并,这样构造可以保证其正确性。
另外机房神犇提供的更强做法:
从子问题的角度考虑,那么对于
n
个点,我们首先通过回答满足了前
代码:
#include "game.h"
#include<iostream>
#include<cstring>
#include<string>
#define N 1500
using namespace std;
int f[N + 5],edge[N + 5][N + 5],m,num[N + 5];
void initialize(int n){
m = n;
for (int i = 0;i < m; ++i) f[i] = i,num[i] = 1;
memset(edge,0,sizeof(edge));
}
inline int find(int x){
return f[x] == x ? x : f[x] = find(f[x]);
}
inline void unionn(int u,int v){ f[u] = v;}
int hasEdge(int u, int v){
int u1 = find(u),v1 = find(v);
if (edge[u1][v1] + 1 == num[u1] * num[v1]){
unionn(u1,v1);
for (int i = 0;i < m; ++i) edge[v1][i] += edge[u1][i],edge[i][v1] = edge[v1][i];
num[v1] += num[u1];
return 1;
}
else {
edge[u1][v1]++;
edge[v1][u1]++;
return 0; }
}
总结:1.构造的时候可以从子问题的角度考虑,逐步放大问题的规模
2.构造也可以从操作的最后一步考虑