poj2749 Building roads

Building roads

题目背景:

poj2749

分析:本题的建边比较繁琐,并且需要二分答案来寻找最小的曼哈顿距离然后2-SAT求解,因此,每一次二分一个上界,然后根据上界limit, 然后根据喜欢讨厌关系和如下关系建边tarjan即可。如还不太清楚2-SAT,可以去看这篇

dist(i, S1) + dist(S1, j) > limit  ó Xi->!Xj  Xj->Xi

dist(i, S2) + dist(S2, j) > limit  ó !Xi->Xj  !Xj->Xi

dist(i, S1) + dist(S1, S2) + dist(S2, j) > limit ó !Xj->!Xi Xi->Xj

dist(i, S2) + dist(S2, S1) + dist(S1, j) > limit ó !Xi->!Xj Xj->Xi

 

Source:

#include 
      
      
       
       
#include 
       
       
        
        
#include 
        
        
         
         
#include 
         
         
          
          
#include 
          
          
            #include 
           
             #include 
            
              #include 
             
               using namespace std; inline void R(int &v) { char c = 0; bool p = true; v = 0; while(!isdigit(c)) { if(c == '-') p = false; c = getchar(); } while(isdigit(c)) { v = (v << 3) + (v << 1) + (c ^ '0'); c = getchar(); } if(!p) v = -v; } const int MAXN = 50000 + 10; const int MAXM = 1000000; stack 
              
                s; int dist[MAXN << 1][2], dis12, tot, first[MAXN << 1], n, a, b; int num[MAXN << 1], low[MAXN << 1], ind, cnt, scc[MAXN << 1]; struct P { int x, y; } point[MAXN], s1, s2; struct node { int next, to; } edge[MAXM]; int like[1010][2], hate[1010][2]; bool exist[MAXN << 1]; inline int dis(int i, int j) { return abs(point[j].y - point[i].y) + abs(point[j].x - point[i].x); } inline void create(int x, int y) { tot++, edge[tot].next = first[x], first[x] = tot, edge[tot].to = y; } void read() { R(n), R(a), R(b), R(s1.x), R(s1.y), R(s2.x), R(s2.y); point[0] = s1, point[n + 1] = s2; for(int i = 1; i <= n; ++i) R(point[i].x), R(point[i].y); for(int i = 1; i <= a; ++i) R(hate[i][0]), R(hate[i][1]); for(int i = 1; i <= b; ++i) R(like[i][0]), R(like[i][1]); } void pre() { dis12 = dis(0, n + 1); for(int i = 1; i <= n; ++i) { dist[i][0] = dis(0, i); dist[i][1] = dis(n + 1, i); } } void build(int x) { for(int i = 1; i <= a; ++i) create(hate[i][0], hate[i][1] + n), create(hate[i][0] + n, hate[i][1]), create(hate[i][1], hate[i][0] + n), create(hate[i][1] + n, hate[i][0]); for(int i = 1; i <= b; ++i) create(like[i][0], like[i][1]), create(like[i][1], like[i][0]), create(like[i][0] + n, like[i][1] + n), create(like[i][1] + n, like[i][0] + n); for(int i = 1; i <= n; ++i) for(int j = i + 1; j <= n; ++j) { if(dist[i][0] + dist[j][0] > x) create(i, j + n), create(j, i + n); if(dist[i][1] + dist[j][1] > x) create(i + n, j), create(j + n, i); if(dist[i][0] + dis12 + dist[j][1] > x) create(i, j), create(j + n, i + n); if(dist[i][1] + dis12 + dist[j][0] > x) create(i + n, j + n), create(j, i); } } void dfs(int cur) { num[cur] = low[cur] = ++ind; exist[cur] = true; s.push(cur); for(int p = first[cur]; p; p = edge[p].next) { if(!num[edge[p].to]) dfs(edge[p].to), low[cur] = min(low[cur], low[edge[p].to]); else if(exist[edge[p].to]) low[cur] = min(low[cur], num[edge[p].to]); } if(num[cur] == low[cur]) { int o = s.top(); cnt++; while(o != cur) exist[o] = false, s.pop(), scc[o] = cnt, o = s.top(); exist[o] = false, s.pop(), scc[o] = cnt; } } void clear() { tot = cnt = ind = 0; memset(first, 0, sizeof(first)); memset(num, 0, sizeof(num)); memset(exist, 0, sizeof(exist)); while(!s.empty()) s.pop(); } bool check(int x) { clear(); build(x); for(int i = 1; i <= (n << 1); ++i) if(!num[i]) dfs(i); for(int i = 1; i <= n; ++i) if(scc[i] == scc[i + n]) return false; return true; } void work() { const int MAXX = 30000000; int l = -1, r = MAXX; while(l + 1 < r) { register int mid = l + r >> 1; if(check(mid)) r = mid; else l = mid; } cout << (r == MAXX ? -1 : r) ; } int main() { read(); pre(); work(); return 0; } 
               
              
             
            
          
         
         
        
        
       
       
      
      

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值