UOJ#26. 【IOI2014】Game

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

另外机房神犇提供的更强做法:
从子问题的角度考虑,那么对于 n 个点,我们首先通过回答满足了前n1个点不被推测出,那么对于第 n 个点,关于它的询问和n1个点是独立的,我们可以在当第 n 个点查询第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.构造也可以从操作的最后一步考虑

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值