HDU 1815 Building roads 二分+2-sat充分理解建图

2024-04-22 07:58

本文主要是介绍HDU 1815 Building roads 二分+2-sat充分理解建图,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题意:给你两个中转点s1,s2,和很多其他的点d{},d{}里面的点只能连接s1或s2,不能同时连接两个,给你一些关系:com(a,b)表示a,b要同时连接同一个中转点,dex(a,b)表示a,b不能同时连接同一个中转点,问你d{}里面的两对点的最大距离的最小值。


想法:看到了最大距离的最小值,显然用二分枚举,这里有一个小优化,我们不容易确定最大的一个距离点对,但是我们可以很容易的找到一个最小的。

这道题就是考建图,分为两个方面:1.com和dex的建图。2.极限距离的限制建图

还有就是一个很重要的一点:建图的时候,你的建边顺序不正确,你的答案也可能超时,这是我的亲身经历,之前以为无所谓的。(但是我不知道为什么?会的留言)

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio> 
#include<stack>
#define inf 0x7fffffff
using namespace std;
const int nd=1000+50;
int N,A,B;
struct node
{int x,y;
}Dian[500+5],s1,s2;
int downlimit;
int fuck[1100][2],sex[1100][2];
struct nodee
{int v,next;
}e[nd*nd*10];
int head[nd],cnt;
int s_1[500+5],s_2[500+5];
int dfn[nd],low[nd],instack[nd],paint[nd],index,col;
stack<int>s;
void Init()
{index=col=1;while(!s.empty()) s.pop();memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));memset(paint,0,sizeof(paint));memset(instack,0,sizeof(instack));memset(head,-1,sizeof(head));cnt=0;
} 
void add(int a,int b)
{e[cnt].v=b;e[cnt].next=head[a];head[a]=cnt++;
}
int MIN(int a,int b)
{if(a<b) return a;return b;
}
void tarjan(int u)
{dfn[u]=low[u]=index++; instack[u]=1;s.push(u);for(int i=head[u];i+1;i=e[i].next){int v=e[i].v;if(!dfn[v]){tarjan(v);low[u]=MIN(low[u],low[v]);}else if(instack[v]){low[u]=MIN(low[u],dfn[v]);}}if(dfn[u]==low[u]){int k=s.top();while(k!=u){s.pop();paint[k]=col;instack[k]=0;k=s.top();}s.pop();paint[u]=col;instack[u]=0;col++;}
}
int abss(int x)
{if(x>0) return x;return -x; 
}
inline int dis(node a,node b)
{return abss(a.x-b.x)+abss(a.y-b.y);
}
void Input()
{scanf("%d%d%d%d",&s1.x,&s1.y,&s2.x,&s2.y);downlimit=inf;for(int i=1;i<=N;i++){scanf("%d%d",&Dian[i].x,&Dian[i].y);s_1[i]=dis(Dian[i],s1);s_2[i]=dis(Dian[i],s2);if(downlimit>s_1[i]) downlimit=s_1[i];if(downlimit>s_2[i]) downlimit=s_2[i];}for(int i=1;i<=A;i++){scanf("%d%d",&fuck[i][0],&fuck[i][1]);}for(int i=1;i<=B;i++){scanf("%d%d",&sex[i][0],&sex[i][1]);}
}
bool judge(int limt)
{Init();for(int i=1;i<=A;i++){int a=fuck[i][0],b=fuck[i][1];add(a,b+N);add(b,a+N);add(b+N,a);add(a+N,b);}for(int i=1;i<=B;i++){int a=sex[i][0],b=sex[i][1];add(a,b);add(a+N,b+N);add(b,a);add(b+N,a+N);}int D=dis(s1,s2);for(int i=1;i<N;i++){for(int j=i+1;j<=N;j++){if(limt<s_1[i]+s_1[j]){//不能都选是 add(i,j+N);add(j,i+N);}if(limt<s_2[i]+s_2[j]){//不能都选否 add(i+N,j);add(j+N,i);}if(limt<s_1[i]+D+s_2[j]){//不能同时i选是,j选否 add(i,j);add(j+N,i+N);}if(limt<s_1[j]+D+s_2[i]){//不能同时i选否,j选是 add(i+N,j+N);add(j,i);}}}for(int i=1;i<=2*N;i++){if(!dfn[i]) tarjan(i);}for(int i=1;i<=N;i++){if(paint[i]==paint[i+N]){return false;}}return true;
}
void treatment()
{int low=downlimit,up=8000000;int ans=-1;while(low<=up){int mid=(low+up)/2;if(judge(mid)){ans=mid;up=mid-1;}else low=mid+1;}printf("%d\n",ans);
}
int main()
{while(~scanf("%d%d%d",&N,&A,&B)){Input();treatment();}return 0;
}



这篇关于HDU 1815 Building roads 二分+2-sat充分理解建图的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/925216

相关文章

无人叉车3d激光slam多房间建图定位异常处理方案-墙体画线地图切分方案

墙体画线地图切分方案 针对问题:墙体两侧特征混淆误匹配,导致建图和定位偏差,表现为过门跳变、外月台走歪等 ·解决思路:预期的根治方案IGICP需要较长时间完成上线,先使用切分地图的工程化方案,即墙体两侧切分为不同地图,在某一侧只使用该侧地图进行定位 方案思路 切分原理:切分地图基于关键帧位置,而非点云。 理论基础:光照是直线的,一帧点云必定只能照射到墙的一侧,无法同时照到两侧实践考虑:关

认识、理解、分类——acm之搜索

普通搜索方法有两种:1、广度优先搜索;2、深度优先搜索; 更多搜索方法: 3、双向广度优先搜索; 4、启发式搜索(包括A*算法等); 搜索通常会用到的知识点:状态压缩(位压缩,利用hash思想压缩)。

hdu2241(二分+合并数组)

题意:判断是否存在a+b+c = x,a,b,c分别属于集合A,B,C 如果用暴力会超时,所以这里用到了数组合并,将b,c数组合并成d,d数组存的是b,c数组元素的和,然后对d数组进行二分就可以了 代码如下(附注释): #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<que

hdu2289(简单二分)

虽说是简单二分,但是我还是wa死了  题意:已知圆台的体积,求高度 首先要知道圆台体积怎么求:设上下底的半径分别为r1,r2,高为h,V = PI*(r1*r1+r1*r2+r2*r2)*h/3 然后以h进行二分 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#includ

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

hdu 2093 考试排名(sscanf)

模拟题。 直接从教程里拉解析。 因为表格里的数据格式不统一。有时候有"()",有时候又没有。而它也不会给我们提示。 这种情况下,就只能它它们统一看作字符串来处理了。现在就请出我们的主角sscanf()! sscanf 语法: #include int sscanf( const char *buffer, const char *format, ... ); 函数sscanf()和

hdu 2602 and poj 3624(01背包)

01背包的模板题。 hdu2602代码: #include<stdio.h>#include<string.h>const int MaxN = 1001;int max(int a, int b){return a > b ? a : b;}int w[MaxN];int v[MaxN];int dp[MaxN];int main(){int T;int N, V;s

hdu 1754 I Hate It(线段树,单点更新,区间最值)

题意是求一个线段中的最大数。 线段树的模板题,试用了一下交大的模板。效率有点略低。 代码: #include <stdio.h>#include <string.h>#define TREE_SIZE (1 << (20))//const int TREE_SIZE = 200000 + 10;int max(int a, int b){return a > b ? a :

hdu 1166 敌兵布阵(树状数组 or 线段树)

题意是求一个线段的和,在线段上可以进行加减的修改。 树状数组的模板题。 代码: #include <stdio.h>#include <string.h>const int maxn = 50000 + 1;int c[maxn];int n;int lowbit(int x){return x & -x;}void add(int x, int num){while