https://www.luogu.org/problemnew/show/P4997

首先是改变气的定义,使得容易计算,这个很好理解。
然后使用并查集,因为要维护整个连通块的性质。

最后的难点在于,落子把同颜色的连通块连接了,但假如本身就是同一个连通块则不应该计数,所以其实连通块的气不应该手动维护,而应该全权交给并查集去处理。

当然去重之后也是对的。

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;const int INF=0x3f3f3f3f;int solve();int main() {
#ifdef Yinkufreopen("Yinku.in","r",stdin);
#endif // Yinkusolve();
}int n;
char g[605][605];inline int id(int i,int j) {return (i-1)*n+j;
}inline void aid(int f,int &i,int &j) {j=f%n;if(j==0)j=n;i=(f-j)/n+1;return;
}int fa[360005];
//并查集
int qi[360005];
//id对应的位置的气,只有并查集的根保存正确的气queue<int> Q[2];int dx[4]= {-1,1,0,0};
int dy[4]= {0,0,-1,1};char col[2]= {'X','O'};int find(int x) {int r=x;while(fa[r]!=r) {r=fa[r];}while(x!=r) {int k=fa[x];fa[x]=r;x=k;}return r;
}void merge(int x,int y) {x=find(x);y=find(y);if(x==y)return;fa[y]=x;return;
}void Exit() {puts("-1 -1");exit(0);
}inline void Show() {cout<<"G:"<<endl;for(int i=1; i<=n; i++) {cout<<g[i]+1<<endl;}cout<<endl;/*cout<<"FA:"<<endl;for(int i=1; i<=n; i++) {for(int j=1; j<=n; j++) {printf("%2d ",fa[id(i,j)]);}cout<<endl;}cout<<endl;*/cout<<"QI:"<<endl;for(int i=1; i<=n; i++) {for(int j=1; j<=n; j++) {qi[id(i,j)]=qi[find(id(i,j))];printf("%2d ",qi[id(i,j)]);}cout<<endl;}cout<<endl;
}bool RollBackOtherColor(int ox,int oy,int th,int ot) {int need=0;for(int k=0; k<4; k++) {int x=ox+dx[k];int y=oy+dy[k];if(x>=1&&x<=n&&y>=1&&y<=n&&g[x][y]==col[ot])if(qi[find(id(x,y))]<=0){need=1;break;}}if(!need)return 0;for(int k=0; k<4; k++) {int x=ox+dx[k];int y=oy+dy[k];if(x>=1&&x<=n&&y>=1&&y<=n&&g[x][y]!='.')qi[find(id(x,y))]++;}return 1;}bool RollBackThisColor(int ox,int oy,int th,int ot,int Qi) {int newQi=Qi;vector<int> visited;for(int k=0; k<4; k++) {int x=ox+dx[k];int y=oy+dy[k];/*这样同一个连通块的气被重复计算了if(x>=1&&x<=n&&y>=1&&y<=n&&g[x][y]==col[th])newQi+=qi[find(id(x,y))];*/if(x>=1&&x<=n&&y>=1&&y<=n&&g[x][y]==col[th]){int r=find(id(x,y));int s=visited.size();bool Visited=0;for(int i=0;i<s;i++){if(visited[i]==r){Visited=1;break;}}if(Visited)continue;visited.push_back(r);newQi+=qi[r];}}/*cout<<"newQi="<<newQi<<endl;cout<<"Qi="<<Qi<<endl;*/if(newQi>0) {//还有气,落子g[ox][oy]=col[th];for(int k=0; k<4; k++) {int x=ox+dx[k];int y=oy+dy[k];if(x>=1&&x<=n&&y>=1&&y<=n&&g[x][y]==col[th])merge(id(ox,oy),id(x,y));}qi[find(id(ox,oy))]=newQi;printf("%d %d\n",ox,oy);//Show();return 0;}for(int k=0; k<4; k++) {int x=ox+dx[k];int y=oy+dy[k];if(x>=1&&x<=n&&y>=1&&y<=n&&g[x][y]!='.')qi[find(id(x,y))]++;}return 1;}int Move(int th,int ot) {while(1) {//Show();//交替下while(1) {//重复下同一种棋,防爆栈if(Q[th].empty()) {Exit();}int f=Q[th].front();Q[th].pop();int x,y;aid(f,x,y);//cout<<"color="<<col[th]<<" ("<<x<<","<<y<<")"<<endl;//已经被落子,重来if(g[x][y]!='.') {//cout<<"RollBack beacuse there is already a piece"<<endl;continue;}int Qi=0;for(int k=0; k<4; k++) {int xx=x+dx[k];int yy=y+dy[k];if(xx>=1&&xx<=n&&yy>=1&&yy<=n) {if(g[xx][yy]!='.')qi[find(id(xx,yy))]--;elseQi++;}}//Show();if(RollBackOtherColor(x,y,th,ot)) {//把另一种颜色提子了,回滚重来//cout<<"RollBack by other color"<<endl;continue;}//那么下这步棋至少不会把另一种棋提子了,接下来看看是不是堵死自己if(RollBackThisColor(x,y,th,ot,Qi)) {//把自己提子了,回滚重来//cout<<"RollBack by this color"<<endl;continue;}//已经被上函数落子break;}//颜色交换swap(th,ot);}return 0;
}void Init() {//初始化并查集for(int i=1; i<=n*n; i++)fa[i]=i;//用并查集连通各部分,每个点和他右边、下边的点连接就可以了for(int i=1; i<=n; i++) {for(int j=1; j<=n; j++) {if(g[i][j]=='.')continue;if(i+1<=n&&g[i][j]==g[i+1][j])merge(id(i,j),id(i+1,j));if(j+1<=n&&g[i][j]==g[i][j+1])merge(id(i,j),id(i,j+1));}}//统计气memset(qi,0,sizeof(qi));//每个空位对各个棋子的贡献for(int i=1; i<=n; i++) {for(int j=1; j<=n; j++) {if(g[i][j]!='.')continue;//插入待使用队列Q[0].push(id(i,j));Q[1].push(id(i,j));for(int k=0; k<4; k++) {int x=i+dx[k];int y=j+dy[k];if(x>=1&&x<=n&&y>=1&&y<=n&&g[x][y]!='.')qi[find(id(x,y))]++;}}}return ;
}int solve() {scanf("%d",&n);for(int i=1; i<=n; i++) {scanf("%s",g[i]+1);}Init();Move(0,1);//先下黑棋return 0;
}

转载于:https://www.cnblogs.com/Yinku/p/10951391.html

洛谷 - P4997 - 不围棋 - 并查集 - 模拟相关推荐

  1. 【洛谷 P7299】 【并查集】 Dance Mooves S

    [洛谷 P7299] [并查集] Dance Mooves S 题目 解题思路 可以先求出k轮后i能到达next[i] 可以发现将会组成由很多个简单环组成的图,它们能到达的点可以共享给同一个环内的 所 ...

  2. 洛谷 - P1111 - 修复公路 - 并查集

    https://www.luogu.org/problemnew/solution/P1111 并查集的水题,水题都错了好多发. 首先并不是有环就退出,而是连通分支为1才退出,每次合并成功连通分支才会 ...

  3. 洛谷 P1967货车运输 并查集+贪心 不需要用LCA!

    题目链接 题目链接 题解 要求所有的路径中最小边长的最大值! 我们贪心的加边,依照边从大往小的方式往里添加,然后合并并查集. 每次当查询分布在两个待合并的并查集的时候,当前的边长就是这次查询的答案. ...

  4. 洛谷P1551 亲戚(并查集)

    题目链接 思路: 并查集的模板题目 关于并查集相关知识可以看此博客 AC代码 #include<iostream> #include<cstdio> #include<a ...

  5. 每日一题——洛谷 P1551 亲戚 (并查集)

    大家好,我是爬行系,今天打卡并查集相关例题 文章目录 并查集 1.概念 2.模板 例题 1.题目描述 2.AC代码 更多练习题 总结 并查集 1.概念 并查集的思想是用一个数组表示了整片森林(pare ...

  6. 解题:洛谷3402 可持久化并查集

    题面 滚下去补学考之前更一发 基于可持久化线段树实现(我不很喜欢"主席树"这个名字),注意不能路径压缩,首先这与可持久化的思想冲突(即尽量利用之前已有的部分,只修改有修改的部分,路 ...

  7. 【洛谷1892】团伙 并查集

    题意 题面说的很清楚 同noip2010关押罪犯 传送门:http://blog.csdn.net/dadatu_zhao/article/details/78806584 #include<i ...

  8. 洛谷专题训练 ——【算法1-1】模拟与高精度

    洛谷题单[算法1-1]模拟与高精度 ACM-ICPC在线模板 题单链接: [算法1-1]模拟与高精度 下面的这一坨都是洛谷题单上的东东 题单简介 恭喜大家完成了第一部分语言入门,相信大家已经可以使用 ...

  9. 【洛谷P4997】不围棋【并查集】【模拟】

    题目大意: 题目链接:https://www.luogu.org/problemnew/show/P4997 「不围棋」是一种非常有趣的棋类游戏. 大家都知道,围棋的「气」是指一个棋子所在的联通块相邻 ...

最新文章

  1. grub2 命令行进入系统
  2. 深入理解js的变量提升和函数提升
  3. 计算机术语设备透明性,计算机中术语透明性是什么意思?
  4. java比赛用多重for_关于 Java 中 for的多重循环
  5. object detection错误Message type object_detection.protos.SsdFeatureExtractor has no field named bat
  6. 常见c#正则表达式类学习整理
  7. linux flush 文件,Linux文件系统学习:io的plug过程-blk_flush_plug_list的情况
  8. ant执行命令的详细参数和Ant自带的系统属性
  9. 今天就来分享一招坐着减肥法~ 办公室“久坐族”也同样适用
  10. Waymo已经开始绘制亚特兰大地图数据,自动驾驶汽车路测地点又添新城
  11. vue用阿里云oss上传图片使用分片上传只能上传100kb以内的解决办法 1
  12. 【预测模型】基于蝙蝠算法优化最小二乘支持向量机lssvm实现数据预测matlab代码
  13. 微信小程序中输出大于号和小于号
  14. 认识c语言程序,认识C语言
  15. 实对称矩阵的若干性质与详细证明
  16. 在linux上运行python脚本(安装pytorch踩坑记录,pyinstaller使用方式,构建docker镜像)
  17. golang语言 []interface{}和interface{}
  18. 带你用selenium IDE的录制第一个自动化测试脚本
  19. 内网时间同步,ntp与ntpdate区别,与ntp服务器搭建
  20. 【动网论坛7.1 sp1 修改】-加强检查注册昵称,防止全数字及简单重复ID注册

热门文章

  1. 如何在Lattice CPLD XO2系列器件中执行TransFR(透明传输)操作?
  2. MQ-2烟雾浓度传感器(STM32F103)
  3. ScrumMaster的教练职责
  4. 视展LED屏幕RS485对接(C语言)
  5. FPGA纯verilog代码实现图像对数变换,提供工程源码和技术支持
  6. Qt实现的红色警戒3修改器
  7. 常用CDK生成Java算法(大数异或)
  8. mysql+把正数变成负数_mysql实现负数转正数的方法
  9. 5年!我对OpenStack的一些看法
  10. Python 那么火,到底可以用来做什么?我们来说说 Python3 的主要应用