给你N组炸弹,每组2个,让你在这N组里面选取N个放置,要求(1)每组只能也必须选取一个(2)炸弹与炸弹之间的半径相等(3)不能相互炸到对方。求最大的可放置半径。
思路:
二分去枚举半径,然后用2sat去判断是否可行,在2sat里,每组炸弹的两个是正常对,任何两组的任何两个距离小于等于mid那么这两个是矛盾对。这样强连通缩短,然后判断有没有一组是在同一个强连通块里的,没有那么就ok继续更新二分查找答案。
#include<stdio.h> #include<string.h> #include<math.h> #include<stack> #define N_node 200 + 10 #define N_edge 100000 + 100 using namespace std; typedef struct { int to ,next; }STAR; typedef struct { double x1 ,x2 ,y1 ,y2; }NODE; STAR E1[N_edge] ,E2[N_edge]; NODE node[111]; int list1[N_node] ,list2[N_node] ,tot; int Belong[N_node] ,cnt; int mark[N_node]; stack<int>st; void add(int a , int b) { E1[++tot].to = b; E1[tot].next = list1[a]; list1[a] = tot; E2[tot].to = a; E2[tot].next = list2[b]; list2[b] = tot; } void DFS1(int s) { mark[s] = 1; for(int k = list1[s] ;k ;k = E1[k].next) { int xin = E1[k].to; if(!mark[xin]) DFS1(xin); } st.push(s); } void DFS2(int s) { mark[s] = 1; Belong[s] = cnt; for(int k = list2[s] ;k ;k = E2[k].next) { int xin = E2[k].to; if(!mark[xin]) DFS2(xin); } } double diss(double x1 ,double y1 ,double x2 ,double y2) { double tmp = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2); return sqrt(tmp); } bool ok(double mid ,int n) { memset(list1 ,0 ,sizeof(list1)); memset(list2 ,0 ,sizeof(list2)); tot = 1; for(int i = 0 ;i < n ;i ++) for(int j = i + 1 ;j < n ;j ++) { int a ,b; double dis = diss(node[i].x1 ,node[i].y1 ,node[j].x1 ,node[j].y1); if(dis <= mid) { a = i * 2 ,b = j * 2; add(a ,b^1) ,add(b ,a^1); } dis = diss(node[i].x1 ,node[i].y1 ,node[j].x2 ,node[j].y2); if(dis <= mid) { a = i * 2 ,b = j * 2 + 1; add(a ,b^1) ,add(b ,a^1); } dis = diss(node[i].x2 ,node[i].y2 ,node[j].x1 ,node[j].y1); if(dis <= mid) { a = i * 2 + 1,b = j * 2; add(a ,b^1) ,add(b ,a^1); } dis = diss(node[i].x2 ,node[i].y2 ,node[j].x2 ,node[j].y2); if(dis <= mid) { a = i * 2 + 1,b = j * 2 + 1; add(a ,b^1) ,add(b ,a^1); } } memset(mark ,0 ,sizeof(mark)); while(!st.empty())st.pop(); for(int i = 0 ;i < n * 2 ;i ++) if(!mark[i]) DFS1(i); memset(mark ,0 ,sizeof(mark)); cnt = 0; while(!st.empty()) { int xin = st.top(); st.pop(); if(mark[xin]) continue; ++cnt; DFS2(xin); } int mk = 0; for(int i = 0 ;i < n * 2 ;i += 2) { if(Belong[i] == Belong[i^1]) mk = 1; } return !mk; } int main () { int n ,i; while(~scanf("%d" ,&n)) { for(i = 0 ;i < n ;i ++) scanf("%lf %lf %lf %lf" ,&node[i].x1 ,&node[i].y1 ,&node[i].x2 ,&node[i].y2); double low ,mid ,up ,ans = 0; low = 0 ,up = 2000000000; for(i = 1 ;i <= 100 ;i ++) { mid = (low + up) / 2; if(ok(mid ,n)) ans = low = mid; else up = mid; } printf("%.2lf " ,ans/2); } return 0; }