本题解同步于luogu

emmm切了近年省选题来写题解啦qwq

该题较其他省选题较水吧(否则我再怎么做的出来

思路是图论做法,做法上楼上大佬已经讲的很清楚了,我来谈谈代码实现上的一些细节

\[\text{设节点1...2n,i}\in\text{1-n表示i行,i}\in\text{(n+1)-2n时表示i-n列}
\]

\[\text{当我们读到一颗绿宝石(x,y,k)时,就从x向y+n连一条权值为k的边}
\]

\[\text{当我们连完边后会发现给一行/一列增加a就相当于把与这个点相连的所有边权值增加a}
\]

\[\text{这个加边权可以转化为加点权}
\]

\[\text{设}onk_i\text{表示在这个节点上的点击次数,}
\]

\[\text{搜索起始节点的初值为与这个节点所连边中权值最小的}
\]

\[\text{那么已知两点i,j以及}edge_{i,j}\text{和}onk_i\text{,那么由题目条件易得}onk_j=edge_{i,j}-onk_i
\]

\[\text{那么直接dfs}
\]

时间复杂度为$$O(T\times(KlogK+K)) = O(TNlogN)$$要改进也行,因为我们对于每个点所连边只要边权最小数所以没必要sort,但当我想到这一点时已经AC本题~

\[Talk\;is\;free\;,\;show\;me\;the\;code
\]

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<vector>
  4. #include<algorithm>
  5. #include<cstring>
  6. #define MAXN 1005
  7. using namespace std ;
  8. inline void read(int &x) {
  9. scanf("%d",&x) ;
  10. }
  11. class getsol {
  12. public:
  13. //========data========
  14. vector<pair<int,int> > edge[MAXN*2] ; //pair第一维是边权,第二维是到达边的编号
  15. int n , m , k , onk[MAXN*2] , inq[MAXN*2] , flag ;//inq表示是否被搜到
  16. //========func========
  17. void add(int x,int y,int v) {
  18. edge[x].push_back(make_pair(v,y)) ; //加边
  19. }
  20. bool check(int u,int v,int w) {
  21. //check , 判断v点是否可行
  22. if(onk[u]+onk[v]!=w) return 0 ;
  23. return 1 ;
  24. }
  25. void dfs(int D) {
  26. //cout<<"DFS : START SEARCH IN DOT "<<D<<endl ;
  27. if(flag==0) return ;
  28. inq[D] = 1 ;
  29. for(auto& i : edge[D]) { //对于每个edge[D]中的元素i
  30. ///cout<<"DFS : SEARCH IN DOT "<<i.second<<endl ;
  31. if(flag==0) return ;
  32. //cout<<"In dot : "<<i.second<<endl ;
  33. int ver = i.second , edgeval = i.first ;
  34. if(inq[ver]) {
  35. if(flag==1) //如果答案还是"Yes"那么更新,这里是一个优化~
  36. flag = check(D,ver,edgeval) ;
  37. continue ;
  38. } else {
  39. onk[ver] = edgeval-onk[D] ;
  40. dfs(ver) ;
  41. }
  42. }
  43. }
  44. void PRINT(int* arr,int n) {
  45. for(int i=1; i<=n; ++i) {
  46. cout<<"arr["<<i<<"] = "<<arr[i]<<endl ;
  47. }
  48. }
  49. void sol() {
  50. flag = true ;
  51. read(n) , read(m) , read(k) ;
  52. //行的编号为1~n
  53. //列的编号为(n+1)~(2*n)
  54. //喵~
  55. for(int i=1; i<=k; ++i) {
  56. int x,y,v ;
  57. read(x) , read(y) , read(v) ;
  58. add(x,y+n,v) ;
  59. add(y+n,x,v) ;
  60. }
  61. //cerr<<"FINISH READ"<<endl ;
  62. for(int i=1; i<=2*n; ++i) sort(edge[i].begin(),edge[i].end()) ;
  63. //cerr<<"FINISH SORT"<<endl ;
  64. for(int i=1; i<=2*n; ++i) {
  65. if(!inq[i]&&flag&&!edge[i].empty()) { // 注意这里判一下vector是否为空。。因为这个RE了两三次
  66. onk[i] = (*edge[i].begin()).first ;
  67. //cerr<<"SEARCH IN DOT "<<i<<endl ;
  68. dfs(i) ;
  69. }
  70. }
  71. if(flag==1) {
  72. for(int i=1; i<=2*n; ++i)
  73. for(auto& j : edge[i])
  74. if(flag==1) //重新check一遍,以免遗漏
  75. flag = check(i,j.second,j.first) ;
  76. }
  77. if(flag) puts("Yes") ;
  78. else puts("No") ;
  79. //PRINT(onk,2*n) ;
  80. }
  81. void clear() {
  82. for(int i=1; i<=2*n; ++i) edge[i].clear() ;
  83. memset(inq,0,sizeof(onk)) ;
  84. memset(onk,0,sizeof(onk)) ;
  85. n = m = k = flag = 0 ;
  86. }
  87. } ;
  88. getsol M ;
  89. int T ;
  90. int main() {
  91. //freopen("solo3.in" , "rb" , stdin) ;
  92. //freopen("solo3.out", "wb" ,stdout) ;
  93. read(T) ;
  94. while(T--) M.sol() , M.clear() ;
  95. }

注意本代码是使用C++11标准写成,代码中不同不同语法处已标注

题解【[FJOI2018]所罗门王的宝藏】的更多相关文章

  1. 【BZOJ5470】[FJOI2018]所罗门王的宝藏()

    [BZOJ5470][FJOI2018]所罗门王的宝藏() 题面 BZOJ 洛谷 有\(n+m\)个变量,给定\(k\)组限制,每次告诉你\(a_i+b_j=c_k\),问是否有可行解. 题解 一道很 ...

  2. bzoj5470 / P4578 [FJOI2018]所罗门王的宝藏

    P4578 [FJOI2018]所罗门王的宝藏 设第$i$行上的值改变了$r1[i]$,第$j$列上的值改变了$r2[i]$ 显然密码$(i,j,c)=r1[i]+r2[j]$ 对于同一列上的两个密码 ...

  3. 洛谷4578 & LOJ2520:[FJOI2018]所罗门王的宝藏——题解

    https://www.luogu.org/problemnew/show/P4578 https://loj.ac/problem/2520 有点水的. 先转换成图论模型,即每个绿宝石,横坐标向纵坐 ...

  4. 洛谷P4578 [FJOI2018]所罗门王的宝藏(dfs)

    题意 题目链接 Sol 对于每个询问\(x, y, c\) 从在\((x, y)\)之间连一条边权为\(c\)的双向边,然后就是解\(K\)个二元方程. 随便带个数进去找找环就行了 #include& ...

  5. P4578 [FJOI2018]所罗门王的宝藏

    传送门 考虑一个位置答案传递性,如果某个位置的红宝石转动确定了,那么会引起连锁反应: 如图,绿色的转动确定了,那么那两个蓝色的转动也确定了 自己手玩一下,发现如果有解那么随便找一个开始然后一路玩下去最 ...

  6. luoguP4578_ [FJOI2018]所罗门王的宝藏

    题意 一个n*m的矩阵,初始值全为0,每一行每一列操作一次可以加1或者减1,问能否操作得到给定矩阵. 分析 行和列的分别的加减是可以相互抵消的,因此我们只需要考虑行的加和列的减. 对于给定矩阵每一个数 ...

  7. 【LOJ】 #2520. 「FJOI2018」所罗门王的宝藏

    题解 发现似乎相当于问一个2000个元的方程组有没有解-- 然而我懵逼啊-- 发现当成图论,两个点之间连一条边,开始BFS,每个点的值赋成边权减另一个点的点权 如果一个环不合法那么肯定无解 代码 #i ...

  8. 【题解】P3959 宝藏 - 状压dp / dfs剪枝

    P3959 宝藏 题目描述 参与考古挖掘的小明得到了一份藏宝图,藏宝图上标出了 n 个深埋在地下的宝藏屋, 也给出了这 n 个宝藏屋之间可供开发的m  条道路和它们的长度. 小明决心亲自前往挖掘所有宝 ...

  9. 题解-FJOI2018 领导集团问题

    题面 FJOI2018 领导集团问题 给一棵树 \(T(|T|=n)\),每个点有个权值 \(w_i\),从中选出一个子点集 \(P=\{x\in {\rm node}|x\in T\}\),使得 \ ...

随机推荐

  1. local feature和global feature的理解

    在计算机视觉方面,global feature是基于整张图像提取的特征,也就是说基于all pixels,常见的有颜色直方图.形状描述子.GIST等:local feature相对来说就是基于局部图像 ...

  2. VLC搭建RTSP服务器的过程

    第一步,打开VLC 第二步:在媒体下拉菜单下!有一个子菜单“串流”如图所示: 点击“串流”子菜单 弹出一个窗口!如下图所示. 添加一个你要串流的本地文件,我刚才传给你的那个长一点的文件. 第三步,会出 ...

  3. 如何通过 Python 和 OpenCV 实现目标数量监控?

    今天我们将利用python+OpenCV实现对视频中物体数量的监控,达到视频监控的效果,比如洗煤厂的监控水龙头的水柱颜色,当水柱为黑色的超过了一半,那么将说明过滤网发生了故障.当然不仅如此,我们看的是 ...

  4. Spring开发环境搭建(Eclipse)

    开发环境搭建,主要包含2部分: Java安装 Eclipse安装 为易于学习,我们只安装这2个部分,对于一般开发学习也足够了.如果你有其他要安装的,酌情添加. Java安装 我们使用Java8: 下载 ...

  5. css 径向渐变

    .example { width: 150px; height: 80px; background: -webkit-radial-gradient(red, green, blue); /* Saf ...

  6. webservice 的简单实现

    1.什么是webservice: 服务端整出一些资源让客户端访问(获取数据) 一个跨语言.跨平台的规范2.作用:跨平台调用.跨语言调用.远程调用 3.什么时候使用webservice: 1.新旧系统之 ...

  7. PHP二维数组--去除指定列含有重复项的数组

    给定二维数组: $arr = array( '0' => array('张三',2,3,4), '1' => array('李四',2,3,4), '2' => array('张三' ...

  8. .chm无法打开问题(windows)

    .chm无法打开问题,尤其是重做系统之后 C:\Windows 确保有hh.exehhctrl.ocxC:\Windows\SysWOW64 确保有itss.dll 否则百度下载hh.exehhctr ...

  9. Floyd--P1119 灾后重建

    题目背景 B地区在地震过后,所有村庄都造成了一定的损毁,而这场地震却没对公路造成什么影响.但是在村庄重建好之前,所有与未重建完成的村庄的公路均无法通车.换句话说,只有连接着两个重建完成的村庄的公路才能 ...

  10. Swift保存RSA密钥到Keychain

    https://www.jianshu.com/p/c1e9bffc76f4 最近项目的需求用到RSA的加密解密,并且需要把公钥信息保存到Keychain里面,网上很多文章都是用Keychain保存账 ...