题意:图上n个点,使每个点都与俩个中转点的其中一个相连(二选一,典型2-sat),并使任意两点最大

距离最小(最大最小,2分答案),有些点相互hata,不能选同一个中转点,有些点相互LOVE,必需选相同中转点

(显然是2sat条件)。

关键:每次二分枚举limit,按limit建图,需要注意的是每条逻辑语句对应两条边(相互对称,逻辑上互为假言易位),

如:必需连通一个点,逻辑语句俩条:a->b,b->a,对应各自假言易位式,4条边。

相信二sat不再是问题了。

#include<iostream>//1200ms/2000ms 1A
#include<queue>
#include<stack>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
struct point
{
int x,y;
};
vector<vector<int> >e(1050);
int n,a,b;point s1,s2; int maxdis=4000001;
point po[505]; point hate[1005]; point love[1005];
int absint(int x)
{
if(x<0)return -x;
return x;
}
int dis(point aa,point bb) //距离
{
return absint(aa.x-bb.x)+absint(aa.y-bb.y);
}
void build(int limit) //每次二分后建图
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) //注意不要加ELSE
{
if(i==j)continue;
if((dis(po[i],s1)+dis(po[j],s2)+dis(s1,s2))>limit) //无法到达了,
{
e[2*i-1].push_back(2*j-1);
e[2*j-2].push_back(2*i-2);
}
if((dis(po[i],s1)+dis(po[j],s1))>limit)
{
e[2*i-1].push_back(2*j-2);
e[2*j-1].push_back(2*i-2);
}
if((dis(po[i],s2)+dis(po[j],s2))>limit)
{
e[2*i-2].push_back(2*j-1);
e[2*j-2].push_back(2*i-1);
}
}
for(int i=0;i<a;i++) //相互憎恨的
{
e[hate[i].x*2-1].push_back(hate[i].y*2-2);
e[hate[i].y*2-1].push_back(hate[i].x*2-2);
e[hate[i].x*2-2].push_back(hate[i].y*2-1);
e[hate[i].y*2-2].push_back(hate[i].x*2-1);
}
for(int i=0;i<b;i++) //相互喜爱的
{
e[love[i].x*2-1].push_back(love[i].y*2-1);
e[love[i].y*2-2].push_back(love[i].x*2-2);
e[love[i].y*2-1].push_back(love[i].x*2-1);
e[love[i].x*2-2].push_back(love[i].y*2-2);
}
}
int vis[1050];int dfn[1050];int low[1050];bool instack[1050];int block[1050];
int times=0; stack<int>s; int num=0;
void tarjan(int u) //下边是2sat缩点判断可行
{
dfn[u]=low[u]=++times;
instack[u]=1;
s.push(u);
int len=e[u].size();
for(int i=0;i<len;i++)
{
int v=e[u][i];
if(!vis[v])
{
vis[v]=1;
tarjan(v);
if(low[u]>low[v])low[u]=low[v];
}
else if(instack[v]&&dfn[v]<low[u])
low[u]=dfn[v];
}
if(dfn[u]==low[u])
{
num++;
int cur;
do{
cur=s.top();s.pop();
instack[cur]=0;
block[cur]=num;
}while(cur!=u);
}
}
bool check(int limit)
{
for(int i=0;i<=2*n-1;i++)
{
e[i].clear();
block[i]=vis[i]=dfn[i]=low[i]=instack[i]=0;
}
num=times=0;
build(limit);
for(int i=0;i<=2*n-1;i++)
if(!vis[i])
{
vis[i]=1;
tarjan(i);
}
for(int i=0;i<=2*n-1;i+=2)
if(block[i]==block[i+1])
return 0;
return 1;
}
int main()
{
scanf("%d%d%d",&n,&a,&b);scanf("%d%d%d%d",&s1.x,&s1.y,&s2.x,&s2.y);
for(int i=1;i<=n;i++)
scanf("%d%d",&po[i].x,&po[i].y);
for(int i=0;i<a;i++)
scanf("%d%d",&hate[i].x,&hate[i].y);
for(int i=0;i<b;i++)
scanf("%d%d",&love[i].x,&love[i].y);
int right=maxdis,left=0,mid;
if(!check(maxdis)){printf("-1\n");return 0;}
while(right>left+1)
{
mid=(right+left)/2;
if(check(mid))
{
right=mid;
}
else
left=mid;
}
if(check(right-1))printf("%d\n",right-1);
else printf("%d\n",right);
return 0;
}

POJ 2749 2SAT判定+二分的更多相关文章

  1. poj 2749 2-SAT问题

    思路:首先将hate和friend建边求其次2-SAT问题,判断是否能有解,没解就输出-1,否则用二分枚举最大的长度,将两个barn的距离小于mid的看做是矛盾,然后建边,求2-SAT问题.找出最优解 ...

  2. poj 2723 二分+2-sat判定

    题意:给出n对钥匙,每对钥匙只能选其中一个,在给出每层门需要的两个钥匙,只要一个钥匙就能开门,问最多能到哪层. 思路:了解了2-SAT判定的问题之后主要就是建图的问题了,这里建图就是对于2*n个钥匙, ...

  3. HDU 1815, POJ 2749 Building roads(2-sat)

    HDU 1815, POJ 2749 Building roads pid=1815" target="_blank" style="">题目链 ...

  4. POJ 3111 K Best ( 二分 )

    题意 : 给出 N 个物品的价值和重量,然后要求选出 K 个物品使得选出来物品的单位重量价值最大,最后输出被选物品的编号. 分析 :  很容易去想先算出每个物品的单位价值然后升序排序取前 K 个,但是 ...

  5. POJ 3273 Monthly Expense二分查找[最小化最大值问题]

    POJ 3273 Monthly Expense二分查找(最大值最小化问题) 题目:Monthly Expense Description Farmer John is an astounding a ...

  6. Java实现 POJ 2749 分解因数(计蒜客)

    POJ 2749 分解因数(计蒜客) Description 给出一个正整数a,要求分解成若干个正整数的乘积,即a = a1 * a2 * a3 * - * an,并且1 < a1 <= ...

  7. poj 2749 Building roads (二分+拆点+2-sat)

    Building roads Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 6229   Accepted: 2093 De ...

  8. POJ 2749 Building roads 2-sat+二分答案

    把爱恨和最大距离视为限制条件,可以知道,最大距离和限制条件多少具有单调性 所以可以二分最大距离,加边+check #include<cstdio> #include<algorith ...

  9. ZOJ 3717 二分+2-sat判定。

    好久没有2-sat了,此题当复习之用,二分求最大值+2-sat判断可行,此题主要跪于题意:The results should be rounded to three decimal places. ...

随机推荐

  1. 版本号比较versioncompare方法,java实现

    测试

  2. EEPROM介绍

    EEPROM( Electrically Erasable Programmable Read Only Memory )全称是电气可擦除可编程只读存储器,是非易失存储器,可以访问到每个字节,容量比较 ...

  3. 在docker容器中运行hello world!

    在docker容器中运行hello world! docker容器可以理解为在沙盒中运行的进程.这个沙盒包含了该进程运行所必须的资源,包括文件系统.系统类库.shell 环境等等.但这个沙盒默认是不会 ...

  4. 秒杀Sublime Text的微软开源代码编辑工具Visual Studio Code

    1. 下载链接: https://code.visualstudio.com/ 2. 秒开一个ASP.NET网站源码 3.编辑CSS颜色支持 4.Git支持 5.常用快捷键 Ctrl+Shift+P ...

  5. codevs 1979 第K个数

     时间限制: 1 s  空间限制: 1000 KB  题目等级 : 黄金 Gold 题目描述 Description 给定一个长度为N(0<n<=10000)的序列,保证每一个序列中的数字 ...

  6. 在同一页面显示多个JavaScript统计图表

    最近我接到一个开发任务,要求就"售后服务客户满意度调查问卷表"里客户填写的反馈答案做一个统计. 问题的例子如下: 您最后一次是何时购买了我们的产品? 服务人员服务态度是否友好.工作 ...

  7. SQLite - SELECT查询

    SQLite - SELECT查询 SQLite SELECT语句用于获取数据从一个SQLite数据库表返回数据结果表的形式.也称为result-sets这些结果表. 语法 SQLite SELECT ...

  8. JDO

    JDO 编辑 本词条缺少名片图,补充相关内容使词条更完整,还能快速升级,赶紧来编辑吧! JDO(Java Data Object )是Java对象持久化的新的规范,也是一个用于存取某种数据仓库中的对象 ...

  9. Python3简明教程(九)—— 文件处理

    文件是保存在计算机存储设备上的一些信息或数据.你已经知道了一些不同的文件类型,比如你的音乐文件,视频文件,文本文件.Linux 有一个思想是“一切皆文件”,这在实验最后的 lscpu 的实现中得到了体 ...

  10. autoHeight # 动态高度添加 用 window.addEventListener('resize', function () {

    动态高度添加 用 window.addEventListener('resize', function () { mounted () { this.init() window.addEventLis ...