zoukankan      html  css  js  c++  java
  • 【BZOJ3993】星际战争(SDOI2015)-二分答案+最大流

    测试地址:星际战争

    做法:注意到答案具有单调性,答案比某一个点大时都有可行解,比这个点小时都没有可行解,于是可以二分答案,转变为判定性问题:在某一个时间t内能否消灭所有敌人?再看这个题目的模型,注意到在时间t内一个武器最多能够削减(t*攻击速度)个单位的装甲值,我们要做的就是把每个武器的攻击力合理分配来消灭所有敌人,这和网络流的模型非常相似,所以我们从源点S向每个武器连接一条边,容量为该时间内该武器最多的输出,再从每个敌人向汇点T连接一条边,容量为该敌人的装甲值,对于武器i,如果它能攻击敌人j,那么从武器i向敌人j连一条容量无限的边。建完图后,求出这个网络的最大流,如果最大流的流量等于所有敌人的装甲值之和,则敌人就都可以被消灭,否则敌人就不可以被全部消灭。对于每个二分到的答案重新建图跑最大流,如果可行则继续二分左半区间,不可行则继续二分右半区间,注意浮点数的相等判断即可。

    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <cmath>
    #include <queue>
    #define eps 1e-8
    #define inf 1000000000
    using namespace std;
    int n,m,first[2510]={0},s=0,t,tot,level[2510];
    double a[55],b[55],l,r,mid,sum,finalans;
    int att[55][55];
    struct edge {int v,next;double f;} e[100010];
    
    void insert(int a,int b,double f)
    {
      e[++tot].v=b,e[tot].f=f,e[tot].next=first[a],first[a]=tot;
    }
    
    bool equal(double a,double b)
    {
      return fabs(a-b)<=eps;
    }
    
    bool makelevel()
    {
      queue<int> q;
      memset(level,-1,sizeof(level));
      level[s]=1;
      q.push(s);
      while(!q.empty())
      {
        int v=q.front();q.pop();
    	if (v==t) return 1;
    	for(int i=first[v];i;i=e[i].next)
    	  if (level[e[i].v]==-1&&!equal(e[i].f,0))
    	  {
    	    level[e[i].v]=level[v]+1;
    		q.push(e[i].v);
    	  }
      }
      return 0;
    }
    
    double dfs(int v,double maxf)
    {
      double ret=0,f;
      if (v==t) return maxf;
      for(int i=first[v];i;i=e[i].next)
        if (!equal(e[i].f,0)&&level[e[i].v]==level[v]+1)
    	{
    	  f=dfs(e[i].v,min(maxf-ret,e[i].f));
    	  e[i].f-=f;
    	  e[i^1].f+=f;
    	  ret+=f;
    	  if (equal(ret,maxf)) return ret;
    	}
      return ret;
    }
    
    bool check(double val)
    {
      tot=1;
      memset(first,0,sizeof(first));
      for(int i=1;i<=m;i++)
        insert(s,i,mid*b[i]),insert(i,s,0);
      for(int i=1;i<=n;i++)
        insert(m+i,t,a[i]),insert(t,m+i,0);
      for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
    	  if (att[i][j]) insert(i,m+j,inf),insert(m+j,i,0);
      
      double ans=0;
      while(makelevel())
      {
        ans+=dfs(s,inf);
      }
      
      return equal(ans,sum);
    }
    
    int main()
    {
      scanf("%d%d",&n,&m);
      t=n+m+1;
      for(int i=1;i<=n;i++)
      {
        scanf("%lf",&a[i]);
        sum+=a[i];
      }
      for(int i=1;i<=m;i++)
        scanf("%lf",&b[i]);
      for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
    	  scanf("%d",&att[i][j]);
      
      l=0;r=sum;
      while(l<=r)
      {
        mid=(l+r)/2;
    	if (check(mid))
    	{
    	  r=mid-eps;
    	  finalans=mid;
    	}
    	else l=mid+eps;
      }
      printf("%.6lf",finalans);
      
      return 0;
    }
    


  • 相关阅读:
    《掌握需求过程》读书笔记3
    《掌握需求过程》读书笔记2
    《掌握需求过程》阅读笔记1
    2017年秋季个人阅读计划 ---《掌握需求过程》第二版 pdf
    问题账户需求分析
    2017年秋季个人阅读计划
    《我们应当怎样做需求分析》阅读笔记
    软件工程概论课个人总结
    第二次冲刺-个人工作总结10
    第二次冲刺-个人工作总结09
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793791.html
Copyright © 2011-2022 走看看