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

本文介绍了一个关于网络流算法的应用案例,通过解决一个X军团与Y军团间的战斗问题,详细展示了如何利用二分时间结合网络流算法来求解复杂场景下的最优时间分配方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 }

 

  代码中有个细节没处理到,影响了效率,欢迎大家评论(我就懒得改了,额)。

转载于:https://www.cnblogs.com/TenderRun/p/5311558.html

资源下载链接为: https://pan.quark.cn/s/f989b9092fc5 HttpServletRequestWrapper 是 Java Servlet API 中的一个工具类,位于 javax.servlet.http 包中,用于对 HttpServletRequest 对象进行封装,从而在 Web 应用中实现对 HTTP 请求的拦截、修改或增强等功能。通过继承该类并覆盖相关方法,开发者可以轻松地自定义请求处理逻辑,例如修改请求参数、添加请求头、记录日志等。 参数过滤:在请求到达处理器之前,可以对请求参数进行检查或修改,例如去除 URL 编码、过滤敏感信息或进行安全检查。 请求头操作:可以修改或添加请求头,比如设置自定义的 Content-Type 或添加认证信息。 请求属性扩展:在原始请求的基础上添加自定义属性,供后续处理使用。 日志记录:在处理请求前记录请求信息,如 URL、参数、请求头等,便于调试和监控。 跨域支持:通过添加 CORS 相关的响应头,允许来自不同源的请求。 HttpServletRequestWrapper 通过继承 HttpServletRequest 接口并重写其方法来实现功能。开发者可以在重写的方法中添加自定义逻辑,例如在获取参数时进行过滤,或在读取请求体时进行解密。当调用这些方法时,实际上是调用了包装器中的方法,从而实现了对原始请求的修改或增强。 以下是一个简单的示例,展示如何创建一个用于过滤请求参数的包装器: 在 doFilter 方法中,可以使用 CustomRequestWrapper 包装原始请求: 这样,每当调用 getParameterValues 方法时,都会先经过自定义的过滤逻辑。 HttpServletRequestWrapper 是 Java Web 开发中一个强大的工具,它提供了灵活的扩展性,允许开发者
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值