zoukankan      html  css  js  c++  java
  • [无聊测试赛] T10 所驼门王的宝藏

    码农题.思维难度中等,难在调试

    建边方法:分别将x和y排序,对每个点,对它旁边所有的x/y连边(如果他需要). 开map记录点的位置,对于每个点,如果他的九宫格之内有其他点,就对他连边

    注意排序会使点的顺序混乱,故需要在状态里将点的id保存

    连完边跑tarjan缩点.易证如果你能到一个环内的某个点,你就可以到达这个环内的每个点.每个环的权值为他里面的点数量.将各个环转化为一个新图

    可以发现新图已经转化为一个DAG.可以选择用dfs/topo来记录答案.这里我选择用dfs.

    dfs每个未经过的点并统计经过这个点能得到的宝藏数量,取最大值

    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <vector>
    #include <unordered_map>
    #include <cstring>
    #include <stack>
    using namespace std;
    const int MAXN = 1e5+5;
    int n,r,c,dp[MAXN],curr,ans;
    
    int pre,dfn[MAXN],low[MAXN],head[MAXN],num[MAXN],in[MAXN];
    unordered_map<int, unordered_map<int,int> > mp, inq;
    vector<int> adj[MAXN],adj2[MAXN],tmp[MAXN];
    stack<int> st;
    int x_[8] = {1,0,-1,0,1,1,-1,-1};
    int y_[8] = {0,1,0,-1,1,-1,1,-1};//九宫格
    bool vis[MAXN];
    struct Edge{
      int x,y,type,id;
    }edge[MAXN],edge2[MAXN];
    inline bool sorted1(Edge a, Edge b){
      return a.x<b.x || (a.x==b.x && a.type==1);
    }//x排序
    inline bool sorted2(Edge a, Edge b){
      return a.y<b.y || (a.y==b.y && a.type==2);
    }//y排序
    inline void add_x(){
      sort(edge+1,edge+n+1,sorted1);
      int prev = 0;
      for (int i=1;i<=n;i++){
        if (edge[i].type!=1) continue;//如果他自己不能连
        int f = edge[i].id;
        int nxt = i-1;
        while(nxt>0){
          if (edge[nxt].x!=edge[i].x) break;
          int t = edge[nxt].id;
          adj[f].push_back(t);
          nxt--;
        }//往左连
        nxt = i+1;
        while(nxt<=n){
          int t = edge[nxt].id;
          if (edge[nxt].x!=edge[i].x) break;
          adj[f].push_back(t);
          nxt++;
        }//往右连
      }
    }
    inline void add_y(){
      sort(edge+1,edge+n+1,sorted2);
      int prev = 0;
      for (int i=1;i<=n;i++){
        if (edge[i].type!=2) continue;
        int f = edge[i].id;
        int nxt = i-1;
        while(nxt>0){//往左
          int t = edge[nxt].id;
          if (edge[nxt].y!=edge[i].y) break;
          adj[f].push_back(t);
          nxt--;
        }
        nxt = i+1;
        while(nxt<=n){//往右
          int t = edge[nxt].id;
          if (edge[nxt].y!=edge[i].y) break;
          adj[f].push_back(t);
          nxt++;
        }
      }
    }
    inline void add_xy(){//九宫格连
      for (int i=1;i<=n;i++){
        if (edge[i].type!=3) continue;
        int f = edge[i].id;
        for (int j=0;j<8;j++){
          int to_x = edge[i].x+x_[j], to_y = edge[i].y+y_[j];
          if (mp[to_x][to_y] ){
            int t = mp[to_x][to_y];
            if (!inq[f][t]){inq[f][t] = true;adj[f].push_back(t);}
          }
        }
      }
    }
    void tarjan(int pos){//裸的tarjan
      st.push(pos);
      vis[pos] = true;
      dfn[pos] = low[pos] = ++pre;
      for (int v : adj[pos]){
        if (!dfn[v]){
          tarjan(v);
          low[pos] = min(low[pos],low[v]);
        }else if (vis[v]) low[pos] = min(low[pos],dfn[v]);
      }
      if (dfn[pos]==low[pos]) {
        curr++;
        while(st.size()){
          int stt = st.top();
          head[stt] = curr;
          tmp[curr].push_back(stt);
          num[curr]++;
          st.pop();
          vis[stt] = false;
          if (stt==pos) break;
        }
      }
    }
    void dfs(int pos){//dfs找子叶权值
      dp[pos] = num[pos];
      int addi = 0;
      for (int v : adj2[pos]){
        if (!dp[v]) dfs(v);
        addi = max(addi,dp[v]);
      }
      dp[pos]+=addi;
    }
    int main(){
      cin >> n >> r >> c;
      for (int i=1;i<=n;i++) {
        cin >> edge[i].x  >> edge[i].y >> edge[i].type;edge[i].id = i;
        edge2[i] = edge[i];
        mp[edge[i].x][edge[i].y] = i;
      }
      add_x();
      add_y();
      add_xy();
      for (int i=1;i<=n;i++) if (!dfn[i]) tarjan(i);
      
      for (int i=1;i<=curr;i++){//建新图
        memset(vis,0,sizeof(vis));
        vis[i] = true;
        for (int u : tmp[i]){
          for (int v : adj[u]){
            if (!vis[head[v]]){
              vis[head[v]] = true;
              adj2[i].push_back(head[v]);
            }
          }
        }
      }
      memset(vis,0,sizeof(vis));
      for (int i=1;i<=curr;i++){//找答案
        if (!vis[i]){
          dfs(i);
          ans = max(ans,dp[i]);
        }
      }
      cout << ans;
    }
    
  • 相关阅读:
    vue 倒计时返回首页
    vue2借助animate.css实现路由动画效果
    CSS3实现文本垂直排列
    button在点击时出现边框
    vue项目中设置背景图片
    Python -处理PDF
    Python学习笔记(1)-列表
    转:Redis 的安装配置介绍
    转:windows xp下如何安装SQL server2000企业版
    转:CodeCube提供可共享、可运行的代码示例
  • 原文地址:https://www.cnblogs.com/DannyXu/p/12536357.html
Copyright © 2011-2022 走看看