zoukankan      html  css  js  c++  java
  • 网络流(二分):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
    ",hi);
    130     return 0;
    131 }
      代码中有个细节没处理到,影响了效率,欢迎大家评论(我就懒得改了,额)。
    尽最大的努力,做最好的自己!
  • 相关阅读:
    C语言初学 使用while语句统计输入字符个数
    C语言初学 比较五个整数并输出最大值和最小值2
    C语言初学 比较五个整数并输出最大值和最小值1
    C语言初学 计算表达式的值 switch的意义
    C语言初学 if-else语句判别在ASCII值中小于32的可控制符的类型
    C语言初学 if-else语句判断俩数的最大值
    C语言初学 计算二元一次方程的问题
    C语言初学 判断闰年的问题
    简单Elixir游戏服务器开篇
    关于Elixir游戏服设计系列
  • 原文地址:https://www.cnblogs.com/TenderRun/p/5311558.html
Copyright © 2011-2022 走看看