1 条题解

  • 0
    @ 2025-8-24 22:47:18

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar FFTotoro
    龙猫

    搬运于2025-08-24 22:47:18,当前版本为作者最后更新于2025-01-23 19:54:03,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    尝试猜测 Maria 会赢的充分条件:令在原图中与结点 11 相邻的点为“关键点”,假设将结点 11 和与其相邻的所有点的边都删去,只需要存在一个连通块中包含奇数个关键点,这个时候 Maria 每次随便选一个还没选过的点挑战就能赢。

    对于其他情况,可以证明我们一定能赢,所以上述条件是充要的。只需要将每个连通块内的关键点两两匹配,并对于每一对匹配的关键点 (ui,vi)(u_i,v_i) 都找出一条 uiu_iviv_i 的简单路径 pip_i,使得对于任意两条不同的路径 pi,pjp_i,p_j,都不存在一条边同时出现在它们之中。

    当 Maria 问到一个关键点时(不妨设为 uiu_i),只需沿着 pip_i 一路挑战到 viv_i,最后挑战结点 11

    考虑每个连通块,求出满足条件的匹配。求出该连通块的一棵生成树,在树上自底而上贪心匹配(能匹配就匹配);由于连通块内关键点个数为偶数,这样匹配是满足条件的。

    放代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef pair<int,int> pii;
    int GetMove();
    void MakeMove(int v);
    bool Check(vector<vector<int> > g){
      int n=g.size();
      vector<bool> w(n),b(n);
      for(int i:g[0])w[i]=true;
      // w[i] 表示点 i 是否是关键点
      for(int i=1;i<n;i++)
        if(!b[i]){
          int c=0;
          function<void(int)> dfs=[&](int u){
            c+=w[u];
            for(int i:g[u])
              if(i&&!b[i])b[i]=true,dfs(i);
          };
          if(b[i]=true,dfs(i);c&1)return false;
        }
      return true;
    } // 判断是否能赢
    void SocialEngineering(int n,int m,vector<pii> e){
      vector<vector<int> > g(n);
      for(auto &[u,v]:e){
        g[--u].emplace_back(--v);
        g[v].emplace_back(u);
      }
      if(!Check(g))return;
      vector<int> id(n,-1);
      vector<vector<int> > pn(n),p;
      // pn[i] 存储了从 i 开始的路径
      // p[i] 存储了最终匹配中的第 i 条路径
      vector<bool> w(n),b(n);
      for(int i:g[0])w[i]=true;
      for(int i=1;i<n;i++)
        if(!b[i]){
          function<int(int)> dfs=[&](int u){
            vector<int> q;
            for(int i:g[u])
              if(i&&!b[i]){
                b[i]=true;
                if(int v=dfs(i);v)
                  q.emplace_back(v);
              }
            if(w[u])q.emplace_back(u);
            while(q.size()>1){
              int x=q.back(); q.pop_back();
              int y=q.back(); q.pop_back();
              auto t=pn[x]; t.emplace_back(u);
              t.insert(t.end(),pn[y].rbegin(),pn[y].rend());
              id[x]=id[y]=p.size(),p.emplace_back(t);
            } // 进行匹配
            if(!q.empty())pn[q[0]].emplace_back(u);
            return q.empty()?0:q[0];
          };
          b[i]=true,dfs(i);
        }
      while(1){
        int x=GetMove();
        if(--x<0)break;
        if(x==p[id[x]].back())
          reverse(p[id[x]].begin(),p[id[x]].end());
        for(int i:p[id[x]])
          if(i!=x)MakeMove(i+1);
        MakeMove(1);
      } // 模拟过程
    }
    
    • 1

    信息

    ID
    8717
    时间
    5000ms
    内存
    256MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者