The 2024 ICPC Kunming Invitational Contest K. Permutation(交互 期望)

分治算法解决交互思维题

在知乎内查看

题目

img

思路来源

img

题解

首先特判n=1的情况,其实也不用问

分治,假设当前解决到[l,r],要递归的vector是x,

维护两个vector L、R,代表下一步要在[l,mid]和[mid+1,r]分治的vector

每次将x random_shuffle后,取出vector尾部的两个u、v,

计分界点为mid,<=mid的全填u,>mid的全填v,看询问出的答案:

  1. 如果为0,说明都询问错了,则交换u、v所在位置,放进对应vector
  2. 如果为2,说明都询问对了,直接放入对应vector
  3. 否则为1,说明u和v位于一边,此时将v塞进del这个vector里,将u和v在并查集上合并,并把u塞回x

重复这个过程,直至x为空或只剩一个元素,

只剩一个元素时,L或R一定已经有元素,

和已经被询问出来的元素再一起询问一次,就能确定出这个元素该放进L还是R

代码中用to数组记录了是放进左边还是放进右边,

这样del里的元素,在并查集上找到其祖先时,可以用to数组确定其应该被放进L还是R

期望次数是6000的,实际跑得飞快,也没被卡掉

代码

#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
typedef long long ll;
typedef double db;
typedef pair<ll,ll> P;
#define fi first
#define se second
#define pb push_back
#define dbg(x) cerr<<(#x)<<":"<<x<<" ";
#define dbg2(x) cerr<<(#x)<<":"<<x<<endl;
#define SZ(a) (int)(a.size())
#define sci(a) scanf("%d",&(a))
#define pt(a) printf("%d",a);
#define pte(a) printf("%d\n",a)
#define ptlle(a) printf("%lld\n",a)
#define debug(...) fprintf(stderr, __VA_ARGS__)
const int N=1e3+10;
int n,ans[N],q[N],par[N],to[N];
int find(int x){
    return par[x]==x?x:par[x]=find(par[x]);
}
int ask(){
    printf("0");
    rep(i,1,n){
        printf(" %d",q[i]);
    }
    printf("\n");
    fflush(stdout);
    int v;
    sci(v);
    return v;
}
void out(){
    printf("1");
    rep(i,1,n){
        printf(" %d",ans[i]);
    }
    printf("\n");
    fflush(stdout);
}
void sol(int l,int r,vector<int>x){
    //printf("l:%d r:%d ",l,r);
    //for(auto &v:x)printf("%d ",v);puts("");
    if(l==r){
        ans[l]=x[0];
        return;
    }
    for(auto &v:x)par[v]=v;
    int mid=(l+r)/2;
    vector<int>L,R,del;
    while(SZ(x)>1){
        random_shuffle(x.begin(),x.end());
        int u=x.back();x.pop_back();
        int v=x.back();x.pop_back();
        rep(i,1,n){
            if(i<=mid)q[i]=u;
            else q[i]=v;
        }
        int w=ask();
        if(!w)L.pb(v),R.pb(u),to[v]=0,to[u]=1;
        else if(w==2)L.pb(u),R.pb(v),to[u]=0,to[v]=1;
        else del.pb(v),x.pb(u),par[v]=u;
    }
    //printf("x:%d L:%d R:%d\n",SZ(x),SZ(L),SZ(R));
    if(SZ(x)==1){
        int u=x[0];
        if(SZ(L)){
            rep(i,1,n){
                if(i<=mid)q[i]=u;
                else q[i]=L[0];
            }
            int w=ask();
            if(!w)R.pb(u),to[u]=1;
            else L.pb(u),to[u]=0;
        }
        else if(SZ(R)){
            rep(i,1,n){
                if(i<=mid)q[i]=R[0];
                else q[i]=u;
            }
            int w=ask();
            if(!w)L.pb(u),to[u]=0;
            else R.pb(u),to[u]=1;
        }
        else{
            assert(false);
        }
    }
    for(auto &v:del){
        int fa=find(v);
        if(!to[fa])L.pb(v);
        else R.pb(v);
    }
    if(SZ(L))sol(l,mid,L);
    if(SZ(R))sol(mid+1,r,R);
}
void sol(){
    if(n==1){
        ans[1]=1;
        out();
        return;
    }
    vector<int>now;
    rep(i,1,n)now.pb(i);
    sol(1,n,now);
    out();
}
int main(){
    srand(time(NULL));
    sci(n);
    sol();
    return 0;
}
//2 3 4 1 5
### 问题分析 2024 ICPC Latin America Championship Problem C, "Clever Cell Choices", 是一道算法竞赛目,通常涉及图论或几何问题目要求选手在一个由正六边形组成的蜂窝状网格中,选择若干个单元格,满足特定的条件。具体条件可能包括选择的单元格之间不能相邻,或者需要最大化某种价值函数。 这类问题通常可以归类为**最大独立集**问题或**动态规划**问题,具体取决于目条件的复杂性。在 ICPC 等高水平编程竞赛中,这类问题往往需要高效的算法设计,例如基于树的动态规划、状态压缩动态规划,或是图论中的最大匹配与独立集算法。 ### 解思路 如果目要求在蜂窝状网格中选择若干单元格,使得任意两个被选中的单元格之间不相邻,并且使得所选单元格的总价值最大,则可以将问题建模为图论中的最大权独立集问题。由于蜂窝结构的特殊性,可以将其视为一个图,每个单元格是一个节点,相邻关系用边表示。由于该图是**二分图**(蜂窝结构可以被证明为二分图),因此可以利用**最大匹配**算法求解最大独立集。 在这种情况下,解法通常包括以下几个步骤: 1. **建模图结构**:将蜂窝网格表示为图,每个单元格为一个节点,相邻的单元格之间建立边。 2. **构建二分图**:由于蜂窝结构是二分图,可以将其划分为两个部分,分别表示为图的两个集合。 3. **最大匹配算法**:使用匈牙利算法或更高效的 Hopcroft-Karp 算法求解最大匹配。 4. **计算最大独立集**:根据二分图的性质,最大独立集的大小等于顶点总数减去最大匹配数。 ### 代码示例 以下是一个简化的 Python 示例,展示如何在二分图中使用 Hopcroft-Karp 算法求解最大匹配问题。实际比赛中可能需要根据意调整图的构建方式和权重处理: ```python from collections import deque def hopcroft_karp(graph, U, V): pair_U = {u: None for u in U} pair_V = {v: None for v in V} dist = {} def bfs(): queue = deque() for u in U: if pair_U[u] is None: dist[u] = 0 queue.append(u) else: dist[u] = float('inf') dist[None] = float('inf') while queue: u = queue.popleft() if dist[u] < dist[None]: for v in graph[u]: if dist[pair_V[v]] == float('inf'): dist[pair_V[v]] = dist[u] + 1 queue.append(pair_V[v]) return dist[None] != float('inf') def dfs(u): if u is not None: for v in graph[u]: if dist.get(pair_V[v], float('inf')) == dist[u] + 1: if dfs(pair_V[v]): pair_V[v] = u pair_U[u] = v return True dist[u] = float('inf') return False return True matching_size = 0 while bfs(): for u in U: if pair_U[u] is None: if dfs(u): matching_size += 1 return matching_size # 示例图结构 graph = { 'A': ['1', '2'], 'B': ['1', '3'], 'C': ['2', '3'], 'D': ['4'] } U = ['A', 'B', 'C', 'D'] V = ['1', '2', '3', '4'] max_matching = hopcroft_karp(graph, U, V) print("Maximum matching size:", max_matching) ``` ### 复杂度分析 - **时间复杂度**:Hopcroft-Karp 算法的时间复杂度为 $ O(E\sqrt{V}) $,其中 $ E $ 是边的数量,$ V $ 是顶点数量。这使得它在大多数竞赛场景中足够高效。 - **空间复杂度**:需要额外存储图的邻接表以及匹配关系,空间复杂度为 $ O(V + E) $。 ### 总结 "Clever Cell Choices" 这类问题通常需要结合图论和高效算法来求解。通过将蜂窝结构建模为二分图,并利用最大匹配算法,可以有效地求解最大独立集问题。实际比赛中,需要注意图的构建方式以及算法的实现细节,以确保程序在时间限制内完成计算。
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小衣同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值