HDU 1815 Building roads(二分+2-SAT)
来源:互联网 发布:在淘宝刷好评犯法吗 编辑:程序博客网 时间:2024/05/29 18:53
题目地址
题意:给你n个农场,S1场地以及S2场地的坐标,要求每个农场要不与S1连,要不就与S2连,并且每个农场之间的连接距离(曼哈顿距离)的最大值最小,现在告诉你a条不可连接限制,表明两个农场不能和同一个场地连接,又给出b种连接限制,表明两个农场要和同一个场地连接。
思路:我们进行二分枚举最大距离,然后来用2-SAT来判断这个距离的可行性,这里的思想与HDU 3622 Bomb Game的思想十分相像,这里比较复杂的就是进行建图的操作,我们对每个农场进行拆点操作(i*2为与S1相连,i*2+1与S2相连),我们怎么判断一个农场不能与S1或S2中的一个相连,当不能和S1相连,我们只要连一条S1->S2,因为判断的是当同一个地方与S1相连又与S2相连就是错误的,所有既然他不能连S1所以外面连一条S1->S2的边,当有这里有边导致他要连向S1的话那样通过这条边就会使得(i*2和i*2+1出现在同一个连通分量中)后面的不能两个同时连,或者一定要同时连的操作也和这个差不多,只要把一个点的S1连向另一个点的S2就好了,这个操作就是2-SAT的核心(可以看我的博客:传送门)。
#include <iostream>#include <cstring>#include <string>#include <queue>#include <vector>#include <map>#include <set>#include <cmath>#include <cstdio>#include <algorithm>#include <iomanip>#define N 6010#define M 1000010//双倍#define LL __int64#define inf 0x3f3f3f3f#define lson l,mid,ans<<1#define rson mid+1,r,ans<<1|1#define getMid (l+r)>>1#define movel ans<<1#define mover ans<<1|1using namespace std;const LL mod = 1000000007;const double eps = 0.001;int n, a, b;int head[N], idx;struct node { int to; int next;}edge[M];struct cows { int x, y;}place[N], dislike[N], like[N], S1, S2;int dis_S1_S2, S[N], dis_S1[N], dis_S2[N];struct two_SAT { int dfn[N], low[N]; int stack[N], top; int belong[N], cnt, num; bool vis[N]; void init() { memset(head, -1, sizeof(head)); memset(belong, 0, sizeof(belong)); memset(dfn, 0, sizeof(dfn)); memset(vis, false, sizeof(vis)); num = cnt = 0; top = 0; idx = 0; } void addedge(int a, int b) { edge[idx].to = b; edge[idx].next = head[a]; head[a] = idx++; } void tarjin(int u) {//缩点 dfn[u] = low[u] = ++num; vis[u] = true; stack[top++] = u; for (int i = head[u]; ~i; i = edge[i].next) { int v = edge[i].to; if (!dfn[v]) { tarjin(v); low[u] = min(low[u], low[v]); } else if (vis[v]) { low[u] = min(low[u], dfn[v]); } } if (dfn[u] == low[u]) { while (true) { int v = stack[--top]; vis[v] = false; belong[v] = cnt;//标记联通分量belong if (u == v) break; } cnt++; } } bool two_sat() { for (int i = 0; i < 2 * n; i++) {//总点数 if (!dfn[i]) tarjin(i); } for (int i = 0; i < 2 * n; i += 2) {//遍历是不是会有一个人有2种可能 if (belong[i] == belong[i + 1]) { return false; } } return true; }}sat;bool check(int num) { sat.init(); bool flag; for (int i = 0; i < n; i++) { flag = false;//i*2为与S1相连,i*2+1与S2相连 if (dis_S1[i] > num) {//不能和S1相连 int x = i * 2;//因为判断的是当同一个地方与S1相连又与S2相连就是错误的,所有既然他不能连S1所以外面连一条S1->S2的边,当有这里有边导致他要连向S1的话那样通过这条边就会使得(i*2和i*2+1出现在同一个连通分量中) int y = i * 2 + 1; sat.addedge(x, y); flag = true; } if (dis_S2[i] > num) {//不能和S2相连 if (flag) { return false; } int x = i * 2 + 1; int y = i * 2; sat.addedge(x, y); } } for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { if (dis_S1[i] <= num&&dis_S1[j] <= num&&dis_S1[i] + dis_S1[j] > num) {//第i个和第j个能够和S1相连的情况 int x = i * 2; int y = j * 2 + 1; sat.addedge(x, y); x = j * 2; y = i * 2 + 1; sat.addedge(x, y); } if (dis_S2[i] <= num&&dis_S2[j] <= num&&dis_S2[i] + dis_S2[j] > num) {//第i个和第j个能够和S2相连的情况 int x = i * 2 + 1; int y = j * 2; sat.addedge(x, y); x = j * 2 + 1; y = i * 2; sat.addedge(x, y); } if (dis_S1[i] <= num&&dis_S2[j] <= num&&dis_S1[i] + dis_S2[j] + dis_S1_S2 > num) {//第i个和S1相连,第j个和S2相连 int x = i * 2; int y = j * 2; sat.addedge(x, y); x = j * 2 + 1; y = i * 2 + 1; sat.addedge(x, y); } if (dis_S2[i] <= num&&dis_S1[j] <= num&&dis_S2[i] + dis_S1[j] + dis_S1_S2 > num) {//第i个和S2相连,第j个和s1相连 int x = i * 2 + 1; int y = j * 2 + 1; sat.addedge(x, y); x = j * 2; y = i * 2; sat.addedge(x, y); } } } for (int i = 0; i < a; i++) {//一定要不同位置 sat.addedge(dislike[i].x * 2, dislike[i].y * 2 + 1); sat.addedge(dislike[i].x * 2 + 1, dislike[i].y * 2); sat.addedge(dislike[i].y * 2, dislike[i].x * 2 + 1); sat.addedge(dislike[i].y * 2 + 1, dislike[i].x * 2); } for (int i = 0; i < b; i++) {//一定要相同位置 sat.addedge(like[i].x * 2, like[i].y * 2); sat.addedge(like[i].x * 2 + 1, like[i].y * 2 + 1); sat.addedge(like[i].y * 2, like[i].x * 2); sat.addedge(like[i].y * 2 + 1, like[i].x * 2 + 1); } return sat.two_sat();}int main() { cin.sync_with_stdio(false); while (cin >> n >> a >> b) { cin >> S1.x >> S1.y >> S2.x >> S2.y; dis_S1_S2 = abs(S1.x - S2.x) + abs(S1.y - S2.y); for (int i = 0; i < n; i++) { cin >> place[i].x >> place[i].y; dis_S1[i] = abs(place[i].x - S1.x) + abs(place[i].y - S1.y); dis_S2[i] = abs(place[i].x - S2.x) + abs(place[i].y - S2.y); } for (int i = 0; i < a; i++) { cin >> dislike[i].x >> dislike[i].y; dislike[i].x--; dislike[i].y--; } for (int i = 0; i < b; i++) { cin >> like[i].x >> like[i].y; like[i].x--; like[i].y--; } int l = 0, r = 100000000; int ans = -1; while (l <= r) { int mid = (l + r) / 2; if (check(mid)) { ans = mid; r = mid - 1; } else l = mid + 1; } cout << ans << endl; } return 0;}
阅读全文
0 0
- hdu 1815 Building roads(二分+2-sat判定)
- POJ 2749 && HDU 1815 Building roads(2-SAT+二分)
- HDU 1815 Building roads(二分+2-SAT)
- Poj 2749 & Hdu 1815 Building roads (2-SAT + 二分 建图)
- HDU - 1815 Building roads (2-SAT)
- HDU 1815, POJ 2749 Building roads(2-sat)
- poj 2749 & hdu 1815 Building roads(2-SAT + 二分,好题)
- HDU 1815 Building roads 二分+2-sat充分理解建图
- poj 2749 Building roads(2-sat+二分)
- poj 2749 Building roads (二分+拆点+2-sat)
- poj 2749 Building roads #二分+2-sat
- POJ 2749 - Building roads(2-SAT+二分)
- |poj 2749|2-SAT|二分|Building roads
- POJ 2749 || HDU 1815 Building roads 2-sat
- 【HDU】1822 Building roads 2-sat
- HDOJ 1815 Building roads(2-sat简介)
- 【2-sat】 HDOJ 1815 Building roads
- poj2749:Building roads(2-SAT)
- node部署到linux服务器
- windows下vim中文乱码的解决方法
- Effective Java(什么是clone、什么是“深拷贝”和“浅拷贝”)
- DAO层
- Android JNI开发(4)--访问Java的实例变量和静态变量
- HDU 1815 Building roads(二分+2-SAT)
- Android 调用系统剪裁工具剪裁用户头像
- Web 解决nginx: [error] open() "/usr/local/nginx/logs/nginx.pid" failed错误
- js截取字符串长度,超出的用省略号代替
- Another MySQL daemon already running with the same unix socket.
- html入门知识点(一)
- 2017-09-20开启博客征程
- 自练题20170726
- 斗地主发牌简单算法