UOJ#26. 【IOI2014】Game

来源:互联网 发布:cda数据分析师考试地点 编辑:程序博客网 时间:2024/06/15 06:12

思路:
我的傻逼做法:
首先一个简单的性质是如果你知道一张完全图的连边情况你可以推测出其连通性。
我们考虑怎样才能满足题目条件,通过枚举最后一步我们发现如果对于一条边(u,v),在询问之前你就可以推测出其联通性,那么一定无法获胜。
所以我们对每个点维护一个并查集,那么对于当前处于两个不同并查集的(u,v),如果两个并查集中之间的点还有边未连,那么(u,v)一定不能联通,但如果都询问了都不连通那会导致对手很容易通过某种策略来判断整个图是不连通的,所以我们就在两个并查集连最后一条边的时候把它们合并,这样构造可以保证其正确性。

另外机房神犇提供的更强做法:
从子问题的角度考虑,那么对于n个点,我们首先通过回答满足了前n1个点不被推测出,那么对于第n个点,关于它的询问和n1个点是独立的,我们可以在当第n个点查询第n次的时候再把它合并,这样就可以轻松出解了。

代码:

#include "game.h"   #include<iostream>#include<cstring>#include<string>#define N 1500using 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.构造也可以从操作的最后一步考虑

0 0
原创粉丝点击