网络流(二分):BZOJ 3993: [SDOI2015]星际战争

Description

   3333年,在银河系的某星球上,X军团和Y军团正在激烈 地作战。在战斗的某一阶段,Y军团一共派遣了N个巨型机器人进攻X军团的阵地,其中第i个巨型机器人的装甲值为Ai。当一个巨型机器人的装甲值减少到0或 者以下时,这个巨型机器人就被摧毁了。X军团有M个激光武器,其中第i个激光武器每秒可以削减一个巨型机器人Bi的装甲值。激光武器的攻击是连续的。这种 激光武器非常奇怪,一个激光武器只能攻击一些特定的敌人。Y军团看到自己的巨型机器人被X军团一个一个消灭,他们急需下达更多的指令。为了这个目标,Y军 团需要知道X军团最少需要用多长时间才能将Y军团的所有巨型机器人摧毁。但是他们不会计算这个问题,因此向你求助。

Input

  第一行,两个整数,N、M。

  第二行,N个整数,A1、A2…AN。

  第三行,M个整数,B1、B2…BM。

  接下来的M行,每行N个整数,这些整数均为0或者1。这部分中的第i行的第j个整数为0表示第i个激光武器不可以攻击第j个巨型机器人,为1表示第i个激光武器可以攻击第j个巨型机器人。

Output

   一行,一个实数,表示X军团要摧毁Y军团的所有巨型机器人最少需要的时间。输出结果与标准答案的绝对误差不超过10-3即视为正确。

Sample Input

2 2
3 10
4 6
0 1
1 1

Sample Output

1.300000

HINT

 【样例说明1】

 

  战斗开始后的前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军团的所有巨型机器人
 
  二分时间,用网络流判断是否合法。
  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 #include <cmath>
  5 using namespace std;
  6 const int maxn=2510;
  7 const int maxm=6010;
  8 const double eps=1e-8;
  9 int cnt=1,fir[maxn],to[maxm],nxt[maxm];
 10 double cap[maxm];
 11 void addedge(int a,int b){
 12     nxt[++cnt]=fir[a];fir[a]=cnt;to[cnt]=b;
 13 }
 14 
 15 int G[51][51];
 16 int A[51],B[51];
 17 
 18 void Build(double k,int n,int m){
 19     int ct=1;
 20     for(int i=1;i<=m;i++)
 21         for(int j=1;j<=n;j++)
 22             if(G[i][j])
 23                 cap[++ct]=1e20,cap[++ct]=0.0;
 24     
 25     for(int i=1;i<=m;i++)
 26         cap[++ct]=1.0*B[i]*k,cap[++ct]=0.0;
 27     
 28     for(int i=1;i<=n;i++)
 29         cap[++ct]=1.0*A[i],cap[++ct]=0.0;                        
 30 }
 31 
 32 int dis[maxn],gap[maxn],q[maxn],front,back;
 33 
 34 void BFS(int S,int T){
 35     memset(dis,0,sizeof(dis));
 36     front=back=1;
 37     dis[T]=1;q[back++]=T;
 38     while(front<back){
 39         int node=q[front++];
 40         for(int i=fir[node];i;i=nxt[i]){
 41             if(dis[to[i]])continue;
 42             dis[to[i]]=dis[node]+1;
 43             q[back++]=to[i];
 44         }
 45     }
 46 }
 47 double mid;
 48 int path[maxn],fron[maxn];
 49 double ISAP(int S,int T){
 50     double ret=0.0;
 51     BFS(S,T);
 52     for(int i=S;i<=T;i++)gap[dis[i]]++;
 53     int p=S;
 54     double f;
 55     memcpy(fron,fir,sizeof(fir));
 56     while(dis[S]<=T+1){
 57         if(p==T){
 58             f=1e20;
 59             while(p!=S){
 60                 f=min(f,cap[path[p]]);
 61                 p=to[path[p]^1];
 62             }
 63             p=T;ret+=f;
 64             while(p!=S){
 65                 cap[path[p]]-=f;
 66                 cap[path[p]^1]+=f;
 67                 p=to[path[p]^1];
 68             }
 69         }
 70         int &ii=fron[p];
 71         for(;ii;ii=nxt[ii])
 72             if(cap[ii]&&dis[p]==dis[to[ii]]+1)
 73                 break;    
 74         if(ii)
 75             path[p=to[ii]]=ii;
 76         else{
 77             if(--gap[dis[p]]==0)break;
 78             int minn=T+1;
 79             for(int i=fir[p];i;i=nxt[i])
 80                 if(cap[i])
 81                     minn=min(minn,dis[to[i]]);
 82             
 83             ii=fir[p];
 84             ++gap[dis[p]=minn+1];        
 85             if(p!=S)
 86                 p=to[path[p]^1];
 87         }        
 88     }
 89     return ret;
 90 }
 91 
 92 int main(){
 93     int n,m;
 94     scanf("%d%d",&n,&m);
 95     for(int i=1;i<=n;i++)
 96         scanf("%d",&A[i]);
 97     for(int i=1;i<=m;i++)
 98         scanf("%d",&B[i]);
 99         
100     for(int i=1;i<=m;i++)
101         for(int j=1;j<=n;j++)
102             scanf("%d",&G[i][j]);
103     
104     for(int i=1;i<=m;i++)
105         for(int j=1;j<=n;j++)
106             if(G[i][j]){
107                 addedge(i,j+m);
108                 addedge(j+m,i);
109             }
110     
111     for(int i=1;i<=m;i++)
112         addedge(0,i),addedge(i,0);
113     
114     double tot=0.0;
115     for(int i=1;i<=n;i++){
116         addedge(i+m,n+m+1);
117         addedge(n+m+1,i+m);
118         tot+=A[i];
119     }
120     double lo=0,hi=1e5;
121     while(hi-lo>=1e-4){
122         mid=(lo+hi)/2.0;
123         Build(mid,n,m);
124         if(fabs(ISAP(0,n+m+1)-tot)<eps)
125             hi=mid;
126         else
127             lo=mid;
128     }
129     printf("%.4lf\n",hi);
130     return 0;
131 }

 

  代码中有个细节没处理到,影响了效率,欢迎大家评论(我就懒得改了,额)。
posted @ 2016-03-23 16:02  TenderRun  阅读(173)  评论(0编辑  收藏  举报