【bzoj3630】[JLOI2014]鏡面通道 對偶圖+計算幾何+網絡流最小割
阿新 • • 發佈:2017-08-18
log ros font eof ext 理學 最小 bool type
2 500 10 600 100
2 700 0 800 100
題目描述
在一個二維平面上,有一個鏡面通道,由鏡面AC,BD組成,AC,BD長度相等,且都平行於x軸,B位於(0,0)。通道中有n個外表面為鏡面的光學元件,光學元件α為圓形,光學元件β為矩形(這些元件可以與其他元件和通道有交集,具體看下圖)。光線可以在AB上任一點以任意角度射入通道,光線不會發生削弱。當出現元件與元件,元件和通道剛好接觸的情況視為光線無法透過(比如兩圓相切)。現在給出通道中所有元件的信息(α元件包括圓心坐標和半徑xi,yi,ri,β元件包括左下角和右上角坐標x1,y1,x2,y2)如上圖,S到T便是一條合法線路。
當然,顯然存在光線無法透過的情況,現在交給你一個艱巨的任務,請求出至少拿走多少個光學元件後,存在一條光線線路可以從CD射出。
下面舉例說明:
現在假設,取走中間那個矩形,那麽就可以構造出一條穿過通道的光路,如圖中的S到T。
輸入
第一行包含兩個整數,x,y,表示C點坐標
第二行包含一個數字,n,表示有n個光學元件
接下來n行
第一個數字如果是1,表示元件α,後面會有三個整數xi,yi,ri分別表示圓心坐標和半徑
第一個數字如果是2,表示元件β,後面會有四個整數x1,y1,x2,y2分別表示左下角和右上角坐標(矩形都平行,垂直於坐標軸)
輸出
輸出包含一行,至少需要拿走的光學元件個數m
樣例輸入
1000 100
6
1 500 0 50
2 10 10 20 100
2 100 10 200 100
2 300 10 400 100
2 700 0 800 100
樣例輸出
2
題解
對偶圖+計算幾何+網絡流最小割
首先有個神奇的物理學結論:水能通過的地方光也一定能通過。
因此直接判定左右通道是否連通即可。而和 bzoj3007 類似,左右連通意味著對偶圖上下不連通。
所以問題轉化為去掉最少的點使得上下不連通。這顯然是個最小割問題。
拆點,如果兩個元件相交,則互相連出點->入點的邊,容量為inf;每個點的入點->出點,容量為1。最小割即為答案。
不過有點惡心的是原件相交的判定,需要耐心= =
#include <queue> #include <cstdio> #include <cstring> #include <algorithm> #define N 610 #define M 400010 using namespace std; typedef long long ll; const int inf = 1 << 30; queue<int> q; int flag[N] , a[N] , b[N] , c[N] , d[N] , head[N] , to[M] , val[M] , next[M] , cnt = 1 , s , t , dis[N]; void add(int x , int y , int z) { to[++cnt] = y , val[cnt] = z , next[cnt] = head[x] , head[x] = cnt; to[++cnt] = x , val[cnt] = 0 , next[cnt] = head[y] , head[y] = cnt; } bool bfs() { int x , i; memset(dis , 0 , sizeof(dis)); while(!q.empty()) q.pop(); dis[s] = 1 , q.push(s); while(!q.empty()) { x = q.front() , q.pop(); for(i = head[x] ; i ; i = next[i]) { if(val[i] && !dis[to[i]]) { dis[to[i]] = dis[x] + 1; if(to[i] == t) return 1; q.push(to[i]); } } } return 0; } int dinic(int x , int low) { if(x == t) return low; int temp = low , i , k; for(i = head[x] ; i ; i = next[i]) { if(val[i] && dis[to[i]] == dis[x] + 1) { k = dinic(to[i] , min(temp , val[i])); if(!k) dis[to[i]] = 0; val[i] -= k , val[i ^ 1] += k; if(!(temp -= k)) break; } } return low - temp; } ll calc(int x , int y) { return (ll)x * x + (ll)y * y; } bool judge(int x , int y) { if(flag[x] + flag[y] == 2) return calc(a[x] - a[y] , b[x] - b[y]) <= (ll)(c[x] + c[y]) * (c[x] + c[y]); else if(flag[x] + flag[y] == 3) { if(flag[x] == 2) swap(x , y); if(calc(a[x] - a[y] , b[x] - b[y]) <= (ll)c[x] * c[x]) return 1; if(calc(a[x] - a[y] , b[x] - d[y]) <= (ll)c[x] * c[x]) return 1; if(calc(a[x] - c[y] , b[x] - b[y]) <= (ll)c[x] * c[x]) return 1; if(calc(a[x] - c[y] , b[x] - d[y]) <= (ll)c[x] * c[x]) return 1; if(abs(a[x] - a[y]) <= c[x] && b[x] >= b[y] && b[x] <= d[y]) return 1; if(abs(a[x] - c[y]) <= c[x] && b[x] >= b[y] && b[x] <= d[y]) return 1; if(abs(b[x] - b[y]) <= c[x] && a[x] >= a[y] && a[x] <= c[y]) return 1; if(abs(b[x] - d[y]) <= c[x] && a[x] >= a[y] && a[x] <= c[y]) return 1; return 0; } else { if(a[x] >= a[y] && a[x] <= c[y] && b[y] >= b[x] && b[y] <= d[x]) return 1; if(a[x] >= a[y] && a[x] <= c[y] && d[y] >= b[x] && d[y] <= d[x]) return 1; if(b[x] >= b[y] && b[x] <= d[y] && a[y] >= a[x] && a[y] <= c[x]) return 1; if(b[x] >= b[y] && b[x] <= d[y] && c[y] >= a[x] && c[y] <= c[x]) return 1; if(c[x] >= a[y] && c[x] <= c[y] && b[y] >= b[x] && b[y] <= d[x]) return 1; if(c[x] >= a[y] && c[x] <= c[y] && d[y] >= b[x] && d[y] <= d[x]) return 1; if(d[x] >= b[y] && d[x] <= d[y] && a[y] >= a[x] && a[y] <= c[x]) return 1; if(d[x] >= b[y] && d[x] <= d[y] && c[y] >= a[x] && c[y] <= c[x]) return 1; return 0; } return 0; } int main() { int h , n , i , j , ans = 0; scanf("%*d%d%d" , &h , &n) , s = 0 , t = 2 * n + 2; for(i = 1 ; i <= n ; i ++ ) { scanf("%d%d%d%d" , &flag[i] , &a[i] , &b[i] , &c[i]); add(i + n + 1 , i , 1); if(flag[i] == 1) { if(b[i] + c[i] >= h) add(s , i + n + 1 , inf); if(b[i] - c[i] <= 0) add(i , t , inf); } if(flag[i] == 2) { scanf("%d" , &d[i]); if(d[i] >= h) add(s , i + n + 1 , inf); if(b[i] <= 0) add(i , t , inf); } for(j = 1 ; j < i ; j ++ ) if(judge(i , j)) add(i , j + n + 1 , inf) , add(j , i + n + 1 , inf); } while(bfs()) ans += dinic(s , inf); printf("%d\n" , ans); return 0; }
【bzoj3630】[JLOI2014]鏡面通道 對偶圖+計算幾何+網絡流最小割