POJ 2296 Map Labeler 2-SAT+二分答案
2016-07-29 22:15
357 查看
这是我的第一篇博文,OI省选翻车几乎爆零,于是从OI狗变成了ACMer
听前辈说多写题解、模板、心得丢博客里会有明显的进步,于是决定开始这么做了。
想着第一篇是要写题解还是要写模板,想了想还是写题解。一道比较简单的题。
题目链接:http://poj.org/problem?id=2296
题目大意:地图上有很多的城市,每个城市需要贴上一个标签,标签是正方形,而且标签的上边或者下边的中点是对应的城市。每个标签大小相同而且不能重叠,求最大的标签的边长。
看到这种求最大或者最小的题就可以尝试二分答案试试。采用二分法之后问题就转化为了边长为x的标签能否放下。由于每个标签只能在城市的上面或者下面,只有两种状态,很容易就想到了2-SAT算法。
考虑每两个城市i,j:
他们之间的横坐标差大于x时,彼此不会产生影响,不需要处理。
他们之间的纵坐标之差大于2x时,也不会互相影响,同样不需要处理。
他们之间的纵坐标差在x和2x之间的时候,他们中间能够放下一个标签,但是不能够放下两个。设他们中间纵坐标大的是large,小的是small,我们可以添加一个条件:large的标签向上or smal的标签向下,这样就能保证中间最多只有一个标签。
他们之间的纵坐标差在(0,x)的时候,他们中间不能放下标签,而且两个点一上一下,那么他们就必须纵坐标大的向上,纵坐标小的向下,我没就能添加两个条件:large的标签向上 or large的标签向上 以及 small的标签向下or small的标签向下。这样就能保证large的标签一定向上,small的标签一定向下。
特别的,当他们纵坐标相等时,只需要满足一上一下即可,不需要一定哪个向上哪个向下。那么我没可以添加两个条件:i的标签向上or j的标签向上 以及 i的标签向下 or j的标签向下。
添加完条件之后,我们只需要跑一遍2-SAT就能够知道边长为x的标签满不满足了。整个算法的时间复杂度是O(O(2-SAT)*logT)的,其中我的O(2-SAT)是O(mn),m是条件的个数,也就是n^2的,总的时间复杂度是O(n^3logT),这样就能够过了。
AC代码:
听前辈说多写题解、模板、心得丢博客里会有明显的进步,于是决定开始这么做了。
想着第一篇是要写题解还是要写模板,想了想还是写题解。一道比较简单的题。
题目链接:http://poj.org/problem?id=2296
题目大意:地图上有很多的城市,每个城市需要贴上一个标签,标签是正方形,而且标签的上边或者下边的中点是对应的城市。每个标签大小相同而且不能重叠,求最大的标签的边长。
看到这种求最大或者最小的题就可以尝试二分答案试试。采用二分法之后问题就转化为了边长为x的标签能否放下。由于每个标签只能在城市的上面或者下面,只有两种状态,很容易就想到了2-SAT算法。
考虑每两个城市i,j:
他们之间的横坐标差大于x时,彼此不会产生影响,不需要处理。
他们之间的纵坐标之差大于2x时,也不会互相影响,同样不需要处理。
他们之间的纵坐标差在x和2x之间的时候,他们中间能够放下一个标签,但是不能够放下两个。设他们中间纵坐标大的是large,小的是small,我们可以添加一个条件:large的标签向上or smal的标签向下,这样就能保证中间最多只有一个标签。
他们之间的纵坐标差在(0,x)的时候,他们中间不能放下标签,而且两个点一上一下,那么他们就必须纵坐标大的向上,纵坐标小的向下,我没就能添加两个条件:large的标签向上 or large的标签向上 以及 small的标签向下or small的标签向下。这样就能保证large的标签一定向上,small的标签一定向下。
特别的,当他们纵坐标相等时,只需要满足一上一下即可,不需要一定哪个向上哪个向下。那么我没可以添加两个条件:i的标签向上or j的标签向上 以及 i的标签向下 or j的标签向下。
添加完条件之后,我们只需要跑一遍2-SAT就能够知道边长为x的标签满不满足了。整个算法的时间复杂度是O(O(2-SAT)*logT)的,其中我的O(2-SAT)是O(mn),m是条件的个数,也就是n^2的,总的时间复杂度是O(n^3logT),这样就能够过了。
AC代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <vector> #include <cstring> #define MAXN 105 using namespace std; struct TwoSAT { int n;//个数 vector<int> G[MAXN*2];//边 bool mark[MAXN*2];//标记 int S[MAXN*2],c;//记录回溯/初始化路线 bool dfs(int x)//标记mark[x]进行搜索 { if(mark[x^1]) return false;//与x相反的被标记 if(mark[x]) return true;//x已经被标记,直接返回成功 mark[x]=true;//标记 S[c++]=x;//记录路径 for(int i=0;i<G[x].size();i++) if(!dfs(G[x][i])) return false;//深搜 return true; } void init(int n) { this->n=n; for(int i=0;i<n*2;i++) G[i].clear(); memset(mark,0,sizeof(mark)); } //x=xval or y=yv a647 al void add_clause(int x,int xval,int y,int yval) { x=x*2+xval;//具体x位置 y=y*2+yval; G[x^1].push_back(y);//有向边x^1到y G[y^1].push_back(x); } bool solve() { for(int i=0;i<n*2;i+=2) if(!mark[i] && !mark[i^1])//需要确定值 { c=0; if(!dfs(i))//i为true不行 { while(c>0) mark[S[--c]]=false;//回溯/初始化 //如果是while(c>=0) mark[c--]=false的话,最后c的值是-1,不能初始化 if(!dfs(i+1)) return false;//i为真假都不行 } } return true; } }; int m; int px[MAXN]; int py[MAXN]; TwoSAT u; int del(int x) { return x>0?x:-x; } void pre(int diff)//0是向上,1是向下出现正方形 { int i,j,large,small; for(i=0;i<m;i++) for(j=0;j<i;j++) { if(del(px[i]-px[j])<diff)//互相会干扰 { if(py[i]>py[j]) large=i,small=j; else large=j,small=i; if(py[large]==py[small])//1上一下 { u.add_clause(i,0,j,0);//必有1向上 u.add_clause(i,1,j,1);//必有1向下 continue; } if(py[large]-py[small]<diff*2)//中间可以有一个 { if(py[large]-py[small]<diff)//中间不能有(大的向上、小的向下 { u.add_clause(large,0,large,0);//large向上或large向上(large必向上 u.add_clause(small,1,small,1);//small向下或small向下(small必向下 } else { u.add_clause(large,0,small,1);//large向上或small向下(中间最多有一个 } } } } } int main() { int T; cin>>T; while(T--) { cin>>m; for(int i=0;i<m;i++) scanf("%d%d",&px[i],&py[i]); int l=0,r=20000,mid; while(r-l>1)//如果是l==r,样例死循环于l=1 r=2 { mid=(l+r)/2; u.init(m); pre(mid); if(u.solve()) l=mid; else r=mid-1; } if(l>r) cout<<"Error!"<<endl; u.init(m); pre(r); if(u.solve()) cout<<r<<endl; else cout<<l<<endl; } }
相关文章推荐
- Codeforces Round #129 (Div. 1)B Little Elephant and Cards
- Visual Studio Code常用设置
- Codeforces Round #129 (Div. 1)B Little Elephant and Cards
- 习题3-7 DNA序列 UVa1368
- 2D平移矩阵与3D平移矩阵
- linux基础命令2
- 广告点击预测
- SPDA-CNN:Unifying Semantic Part Detection and Abstraction for Fine-grained Recognition
- 进阶项目6.1-两人生日差
- nyoj 325 zb的生日
- android 坐标问题
- Callable、Future和FutureTask
- codeforces 22E XOR on Segment 线段树
- 上传docker镜像到hub.docker
- UVa Live (LA) 3644 典型并查集
- HDU 3366 Passage (概率DP)
- 20160729 其他小代码
- poj 2367 topo 排序
- poj 1860 Currency Exchange
- 【POJ2155】Matrix-二维树状数组+前缀和