zoukankan      html  css  js  c++  java
  • Poj2296

    题意:给定n个点,然后在每个点在一个正方形的上边或者下边的中点,并且所有的正方形等大且不能重叠。求正方形最大的边长是多少。

    思路:很明显的二分边长+判定。不过判定要用到2-sat,算是2-sat的入门题吧。

           所谓的2-sat,就是对于若干个bool不等式,然后对于会互相干扰(即不能同时成立的),连边处理,然后对于每一块枚举一个点的值,判断是否可行。出现冲突即无解。具体看代码吧。

    下面2-sat部分是LRJ的模板,写的挺清晰的。。

      1 /*
      2  * Author:  Yzcstc
      3  * Created Time:  2014/3/8 13:40:50
      4  * File Name: Poj2296.cpp
      5  */
      6 #include<cstdio>
      7 #include<iostream>
      8 #include<cstring>
      9 #include<cstdlib>
     10 #include<cmath>
     11 #include<algorithm>
     12 #include<string>
     13 #include<map>
     14 #include<set>
     15 #include<vector>
     16 #include<queue>
     17 #include<stack>
     18 #include<ctime>
     19 #define M0(x) memset(x, 0, sizeof(x))
     20 #define rep(i, a, b) for (int i = (a); i <= (b); ++i)
     21 #define red(i, a, b) for (int i = (a); i >= (b); --i)
     22 #define PB push_back
     23 #define Inf 0x3fffffff
     24 #define eps 1e-8
     25 #define maxn 500
     26 typedef long long LL;
     27 using namespace std;
     28 struct TwoSat{
     29      int n;
     30      vector<int> G[maxn * 2];
     31      bool mark[maxn * 2];
     32      int S[maxn * 2], c;
     33      bool dfs(int x){ // 搜索一组解 
     34           if (mark[x^1]) return false; //出现冲突 
     35           if (mark[x]) return true;
     36           mark[x] = true;
     37           S[c++] = x;
     38           for (int i = 0; i < G[x].size(); ++i)
     39               if (!dfs(G[x][i])) return false;
     40           return true;
     41      }
     42 
     43      void init(int n){
     44           this->n = n;
     45           for (int i = 0; i < 2 * n; ++i)
     46               G[i].clear();
     47           memset(mark, 0, sizeof(mark));
     48      }
     49 
     50      void add_clause(int x, int xv, int y, int yv){
     51            x = x * 2 + xv;
     52            y = y * 2 + yv; //x,y不能同时存在,那么如果选了y,合法解必定要选x^1
     53            G[x^1].push_back(y);  
     54            G[y^1].push_back(x);
     55      }
     56 
     57      bool solve(){
     58            for (int i = 0; i < n * 2; i += 2)
     59                if (!mark[i] && !mark[i+1]){
     60                     c = 0;
     61                     if (!dfs(i)){ //枚举2种取值都无解 
     62                           while (c > 0) mark[S[--c]] = false;
     63                           if (!dfs(i+1)) return false;
     64                     }
     65                }
     66            return true;
     67      }
     68 } Sat;
     69 
     70 int n, X[200], Y[200], T;
     71 
     72 void init(){
     73     scanf("%d", &n);
     74     for (int i = 0; i < n; ++i)
     75         scanf("%d%d", &X[i], &Y[i]);
     76 }
     77 
     78 bool check(int r){
     79      Sat.init(n);
     80      for (int i = 0; i < n; ++i)
     81          for (int j = i + 1; j < n; ++j) if (i != j){ //分类讨论冲突情况 
     82               if (Y[i] < Y[j]){
     83                     if (Y[j] - Y[i] < r && abs(X[i] - X[j]) < r) Sat.add_clause(i, 0 , j, 0);
     84                     if (Y[j] - Y[i] < 2 * r && abs(X[i] - X[j]) < r) Sat.add_clause(i, 1 , j, 0);
     85                     if (Y[j] - Y[i] < r && abs(X[i] - X[j]) < r) Sat.add_clause(i, 1 , j, 1);
     86               }
     87                if (Y[i] > Y[j]){
     88                     if (Y[i] - Y[j] < r && abs(X[i] - X[j]) < r) Sat.add_clause(i, 0 , j, 0);
     89                     if (Y[i] - Y[j] < 2 * r && abs(X[i] - X[j]) < r) Sat.add_clause(i, 0 , j, 1);
     90                     if (Y[i] - Y[j] < r && abs(X[i] - X[j]) < r) Sat.add_clause(i, 1 , j, 1);
     91               }
     92               if (Y[i] == Y[j]){
     93                     if (abs(X[i] - X[j]) < r) Sat.add_clause(i, 0 , j, 0);
     94                     if (abs(X[i] - X[j]) < r) Sat.add_clause(i, 1 , j, 1);
     95               }
     96          }
     97      return Sat.solve();
     98 }
     99 
    100 void solve(){
    101     int l = 0, r = 40000, mid;
    102     int cnt = 0, ans = 0;
    103     while (l <= r){ //二分答案 
    104         mid = (l + r) >> 1;
    105         if (check(mid)) { ans = mid, l = mid + 1;}
    106         else r = mid - 1;
    107     }
    108     printf("%d
    ",ans);
    109 }
    110 
    111 int main(){
    112     freopen("a.in", "r", stdin);
    113     freopen("a.out", "w", stdout);
    114     scanf("%d", &T);
    115     while (T--){
    116          init();
    117          solve();
    118     }
    119     fclose(stdin);  fclose(stdout);
    120     return 0;
    121 }
     
  • 相关阅读:
    6、加法算术
    5、找出最大和最小的数
    4、计算并输出圆的面积和周长
    2、函数y=f(x)
    1、两数的平方和
    单片机中断寄存器知识点总结
    创建PCB原理图的模板
    电机知识
    结合实例谈谈航拍全景的方法和技巧
    航拍技巧
  • 原文地址:https://www.cnblogs.com/yzcstc/p/3588099.html
Copyright © 2011-2022 走看看