1. 程式人生 > >BZOJ3993 [SDOI2015]星際戰爭 【二分 + 網絡流】

BZOJ3993 [SDOI2015]星際戰爭 【二分 + 網絡流】

HA 結果 誤差 include 輸出 正在 void pty getch

題目

3333年,在銀河系的某星球上,X軍團和Y軍團正在激烈地作戰。在戰鬥的某一階段,Y軍團一共派遣了N個巨型機器人進攻X軍團的陣地,其中第i個巨型機器人的裝甲值為Ai。當一個巨型機器人的裝甲值減少到0或者以下時,這個巨型機器人就被摧毀了。X軍團有M個激光武器,其中第i個激光武器每秒可以削減一個巨型機器人Bi的裝甲值。激光武器的攻擊是連續的。這種激光武器非常奇怪,一個激光武器只能攻擊一些特定的敵人。Y軍團看到自己的巨型機器人被X軍團一個一個消滅,他們急需下達更多的指令。為了這個目標,Y軍團需要知道X軍團最少需要用多長時間才能將Y軍團的所有巨型機器人摧毀。但是他們不會計算這個問題,因此向你求助。

輸入格式

第一行,兩個整數,N、M。

第二行,N個整數,A1、A2…AN。
第三行,M個整數,B1、B2…BM。
接下來的M行,每行N個整數,這些整數均為0或者1。這部分中的第i行的第j個整數為0表示第i個激光武器不可以攻擊第j個巨型機器人,為1表示第i個激光武器可以攻擊第j個巨型機器人。

輸出格式

一行,一個實數,表示X軍團要摧毀Y軍團的所有巨型機器人最少需要的時間。輸出結果與標準答案的絕對誤差不超過10-3即視為正確。

輸入樣例

2 2

3 10

4 6

0 1

1 1

輸出樣例

1.300000

提示

戰鬥開始後的前0.5秒,激光武器1攻擊2號巨型機器人,激光武器2攻擊1號巨型機器人。1號巨型機器人被完全摧毀,2號巨型機器人還剩余8的裝甲值;

接下來的0.8秒,激光武器1、2同時攻擊2號巨型機器人。2號巨型機器人被完全摧毀。

對於全部的數據,1<=N, M<=50,1<=Ai<=105,1<=Bi<=1000,輸入數據保證X軍團一定能摧毀Y軍團的所有巨型機器人

題解

明顯是網絡流建圖
S連激光武器
機器人連T容量為生命值
可以攻擊的對象之間連INF的邊

然後二分時間,乘上各個武器單位傷害賦值為S到其的邊上
跑一遍最大流看看能不能跑滿

#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring> #include<algorithm> #define LL long long int #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt) #define REP(i,n) for (int i = 1; i <= (n); i++) #define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<‘ ‘; puts(""); #define cls(s) memset(s,0,sizeof(s)) #define eps 1e-9 using namespace std; const int maxn = 105,maxm = 100005,INF = 1000000000; inline int read(){ int out = 0,flag = 1; char c = getchar(); while (c < 48 || c > 57){if (c == ‘-‘) flag = -1; c = getchar();} while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();} return out * flag; } int h[maxn],ne = 2; struct EDGE{int to,nxt; double f;}ed[maxm]; inline void build(int u,int v,double f){ ed[ne] = (EDGE){v,h[u],f}; h[u] = ne++; ed[ne] = (EDGE){u,h[v],0}; h[v] = ne++; } int d[maxn],vis[maxn],cur[maxn],S,T; bool bfs(){ cls(d); cls(vis); vis[S] = true; queue<int> q; q.push(S); int u; while (!q.empty()){ u = q.front(); q.pop(); Redge(u) if (fabs(ed[k].f) > eps && !vis[to = ed[k].to]){ d[to] = d[u] + 1; vis[to] = true; if (to == T) return true; q.push(to); } } return vis[T]; } double dfs(int u,double minf){ if (u == T || fabs(minf) < eps) return minf; double f,flow = 0; int to; if (cur[u] == -1) cur[u] = h[u]; for (int& k = cur[u]; k; k = ed[k].nxt){ if (d[to = ed[k].to] == d[u] + 1 && fabs(f = dfs(to,min(minf,ed[k].f))) >= eps){ ed[k].f -= f; ed[k ^ 1].f += f; flow += f; minf -= f; if (fabs(minf) < 0) break; } } return flow; } double maxflow(){ double flow = 0; while (bfs()){ memset(cur,-1,sizeof(cur)); flow += dfs(S,INF); } return flow; } int n,m; double sum,a[maxn],b[maxn]; int G[maxn][maxn]; bool check(double t){ memset(h,0,sizeof(h)); ne = 2; for (int i = 1; i <= m; i++) build(S,n + i,t * b[i]); for (int i = 1; i <= n; i++) build(i,T,a[i]); REP(i,m) REP(j,n) if (G[i][j]) build(n + i,j,INF); return fabs(maxflow() - sum) < eps; } int main(){ n = read(); m = read(); S = 0; T = n + m + 1; REP(i,n) sum += (a[i] = read()); REP(i,m) b[i] = read(); REP(i,m) REP(j,n) G[i][j] = read(); double l = 0,r = 5000000,mid; while (r - l > 1e-6){ mid = (l + r) / 2; if (check(mid)) r = mid; else l = mid; } printf("%.6lf\n",(l + r) / 2); return 0; }

BZOJ3993 [SDOI2015]星際戰爭 【二分 + 網絡流】