zoukankan      html  css  js  c++  java
  • P3324 [SDOI2015]星际战争

    传送门:https://www.luogu.org/problemnew/show/P3324

     

    首先瞅一眼数据范围,发现m, n都很小,所以就可以初步断定这是一道网络流的题。

     

    因为题中说每一个武器只能攻击特定的机器人,所以可以想象成这把武器有一条指向该机器人的边,那流量是多少呢?这是不确定的,因为武器攻击机器人的策略是不知道的。不过有一点可以确定,就是在时间t内,这把武器造成的伤害一定是b[i] * t,如果把武器i和源点连一条边,那么这条边的容量就是b[i] * t。

    在考虑每一个机器人的装甲值,如果给个机器人i和汇点建立一条边,那么容量就是a[i]。这样我们就成功建立了一个图。

    然后对 t 进行二分,如果在当时间为 t 时,到汇点的流量是sum(a[i]),那么就说明所有机器人都被打败了,就在左区间二分,否则说明 t 取小了,就在右区间二分。

    因为题中说输出结果与标准答案的绝对误差不超过10-3即视为正确,所以我们把防御值扩大10000倍,这样在long long 范围内就可以解决了。

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<cmath>
      4 #include<algorithm>
      5 #include<cstring>
      6 #include<cstdlib>
      7 #include<cctype>
      8 #include<stack>
      9 #include<queue>
     10 #include<vector>
     11 using namespace std;
     12 #define enter printf("
    ")
     13 #define space printf(" ")
     14 #define Mem(a) memset(a, 0, sizeof(a));
     15 typedef long long ll;
     16 typedef double db;
     17 const int INF = 0x3f3f3f3f;
     18 const db eps = 1e-8;
     19 const int maxn = 2e5 + 5;
     20 inline ll read()
     21 {
     22     ll ans = 0;
     23     char ch = getchar(), last = ' ';
     24     while(!isdigit(ch)) {last = ch; ch = getchar();}
     25     while(isdigit(ch))
     26     {
     27         ans = ans * 10 + ch - '0'; ch = getchar();
     28     }
     29     if(last == '-') ans = -ans;
     30     return ans;
     31 }
     32 inline void write(ll x)
     33 {
     34     if(x < 0) putchar('-'), x = -x;
     35     if(x >= 10) write(x / 10);
     36     putchar(x % 10 + '0');    
     37 }
     38 //mrclr//
     39 
     40 int n, m, t;
     41 ll a[60], b[60];
     42 bool s[60][60];
     43 struct Edge
     44 {
     45     int from, to;
     46     ll cap, flow;
     47 };
     48 vector<Edge> edges;
     49 vector<int> G[maxn];
     50 
     51 void init()
     52 {
     53     edges.clear();
     54     for(int i = 0; i < maxn; ++i) G[i].clear();
     55     
     56 }
     57 void addEdge(int from, int to, ll w)            //以下就是网络流的板子了 
     58 {
     59     edges.push_back((Edge){from, to, w, 0});
     60     edges.push_back((Edge){to, from, 0, 0});
     61     int sz = edges.size();
     62     G[from].push_back(sz - 2);
     63     G[to].push_back(sz - 1);
     64 }
     65 
     66 int dis[maxn];
     67 bool vis[maxn];
     68 bool bfs()
     69 {
     70     Mem(vis);
     71     queue<int> q;
     72     q.push(0); vis[0] = 1;
     73     dis[0] = 0;
     74     while(!q.empty())
     75     {
     76         int now = q.front(); q.pop();
     77         for(int i = 0; i < (int)G[now].size(); ++i)
     78         {
     79             Edge& e = edges[G[now][i]];
     80             if(!vis[e.to] && e.cap > e.flow)
     81             {
     82                 vis[e.to] = 1;
     83                 dis[e.to] = dis[now] + 1;
     84                 q.push(e.to);
     85             }
     86         }
     87     }
     88     return vis[t];
     89 }
     90 int cur[maxn];
     91 ll dfs(int now, ll a)
     92 {
     93     if(now == t || !a) return a;
     94     ll flow = 0, f;
     95     for(int& i = cur[now]; i < (int)G[now].size(); ++i)
     96     {
     97         Edge& e = edges[G[now][i]];
     98         if(dis[e.to] == dis[now] + 1 && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0)
     99         {
    100             e.flow += f;
    101             edges[G[now][i] ^ 1].flow -= f;
    102             flow += f; a -= f;
    103             if(!a) break;
    104         }
    105     }
    106     return flow;
    107 }
    108 
    109 ll maxflow()
    110 {
    111     ll flow = 0;
    112     while(bfs())
    113     {
    114         Mem(cur);
    115         flow += dfs(0, (ll)INF * INF);
    116     }
    117     return flow;
    118 }
    119 
    120 ll sum = 0;
    121 
    122 bool judge(ll tp)
    123 {
    124     init();
    125     for(int i = 1; i <= m; ++i) addEdge(0, i, b[i] * tp);        //把武器和源点建立一条容量为b[i] * time 的边 
    126     for(int i = 1; i <= n; ++i) addEdge(i + m, t, a[i]);        //把机器人和汇点建立一条容量为a[i]的边 
    127     for(int i = 1; i <= m; ++i)
    128         for(int j = 1; j <= n; ++j)
    129             if(s[i][j]) addEdge(i, j + m, INF);            
    130     //如果武器i能攻击机器人j,就建边,容量无穷,因为武器i有b[i] * time的限制 
    131 //    printf("%lld %lld
    ", maxflow(), sum);                
    132     //调试的时候请不要这么写,因为maxflow()跑完后已经成残量网络了,在上面跑自然不对 
    133     return maxflow() == sum;
    134 }
    135 
    136 int main()
    137 {
    138     n = read(); m = read();            //防御值扩大1e4倍 
    139     t = n + m + 1;
    140     for(int i = 1; i <= n; ++i) {a[i] = read(); a[i] *= 10000; sum += a[i];}
    141     for(int i = 1; i <= m; ++i) b[i] = read();
    142     for(int i = 1; i <= m; ++i)
    143         for(int j = 1; j <= n; ++j)
    144             {int x = read(); s[i][j] = x;}
    145     ll L = 0, R = (ll)INF * (ll)INF;
    146     while(L < R)
    147     {
    148         int mid = (L + R) >> 1;
    149         if(judge(mid)) R = mid;
    150         else L = mid + 1;
    151     }
    152     printf("%.5lf
    ", (double)L / 10000);
    153     return 0;
    154 }
  • 相关阅读:
    *关于如何获取指定表的指定字段的数据类型的方法
    *检查表是否存在
    *用Sql添加删除字段,判断字段是否存在的方法
    *MSSQL三个关键系统表
    *系统表的应用
    VC++ ADO编程入门简介
    int i=0; i=i++ System.out.Println(i)
    Microsoft Visual C++ 6.0 关联源代码
    VC ADO接口详解
    程序员每年该做的事
  • 原文地址:https://www.cnblogs.com/mrclr/p/9418440.html
Copyright © 2011-2022 走看看