• CF#366 704D Captain America 上下界网络流


    CF上的题,就不放链接了,打开太慢,直接上题面吧:

    平面上有n个点, 第 i 个点的坐标为 ($X_i ,Y_i$), 你需要把每个点
    染成红色或者蓝色, 染成红色的花费为 r , 染成蓝色的花费为 b .
    有m个限制条件, 有两种类型, 第一种类型为$x = l_i$ 上的红点
    与蓝点个数差的绝对值不超过 $d_i$, 第二种类型为$y= l_i$ 上的红
    点与蓝点个数差的绝对值不超过 $d_i$.

    题解:

      表示这题真的写到失去理想,因为是第一次写带上下限的网络最大流,一开始就把建图和统计代价理解错了好多次。。。

      首先我们可以观察到r, b是固定的,假设r比b小,那么我们就肯定要让涂红色尽可能多,这样才会更优。

      因此我们就不用考虑这个代价了,只需要找到一个合法的方案且使得涂红色的尽可能多即可。

      由于一个点要么涂红,要么涂蓝,因此我们并不需要求出涂蓝的个数,因为只要知道涂红的个数,涂蓝的个数自然就知道了。

      因此现在问题就被简化为了:

        二维平面上有n个点,有m个限制,要求被选中的点尽可能多。

      对于任何一个限制,假设这条线上有num个点,那么我们可以得出被选中点的上限和下限:$[frac{num - d}{2}, frac{num + d}{2}]$。

      而对于任何一个点是否被选,也可以看做有一个上限和下限$[0,1]$,即要么不选,要么选一个。
      那么我们将行和列分别用点表示,如果有点(x, y),那么从第x行向第y列连一条[0, 1]的边.

      对于x的限制,从s 到第x行连[下限,上限]的边。

      然后跑带上下限的最大流就可以知道最多选多少点了。

      如何不知道带上下限最大流怎么写请看:算法学习——带上下界网络流

      这题的建图因为还要离散化,所以写起来十分恶心。。。。

      代码比较冗长,建议只看思路。

      (注意在cf上提交的时候只能用I64d,不能用lld)

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define R register int
      4 #define AC 500000
      5 #define ac 2000000
      6 #define inf 2139062143
      7 #define INF 2139062143
      8 #define LL long long
      9 
     10 int n, m, g, s, t, ss, ff, ww, tt, top1, top2, got, must;
     11 int cnt1, cnt2, x, head, tail, addflow;
     12 int Head[AC], Next[ac], belong[ac], date[ac], haveflow[ac], tot = 1;
     13 int lim1_x[AC], lim2_x[AC], lim1_y[AC], lim2_y[AC], q[AC];
     14 int num1[AC], num2[AC], q1[AC], q2[AC], c[AC], have[AC], good[AC], last[AC];
     15 bool z[AC], flag, vis1[AC], vis2[AC];
     16 LL d[AC], ans, red, blue;
     17 
     18 struct node{
     19     int x, y;
     20 }p[AC];
     21 
     22 inline int read()
     23 {
     24     int x = 0;char c = getchar();
     25     while(c > '9' || c < '0') c = getchar();
     26     while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
     27     return x;
     28 }
     29 
     30 inline void add(int f, int w, int up, int down)
     31 {
     32     belong[tot] = f, date[++tot] = w, Next[tot] = Head[f], Head[f] = tot, haveflow[tot] = up - down, d[f] -= down;
     33     date[++tot] = f, Next[tot] = Head[w], Head[w] = tot, haveflow[tot] = 0, d[w] += down;
     34     if(w == tt) must += up - down;
     35 //    printf("%d ---> %d : %d
    ", f, w, up - down); 
     36 }
     37 
     38 inline void upmin(int &a, int b)
     39 {
     40     if(b < a) a = b;
     41 }
     42 
     43 inline void upmax(int &a, int b)
     44 {
     45     if(b > a) a = b;
     46 }
     47 
     48 inline int half1(int x)
     49 {
     50     int l = 1, r = cnt1, mid; 
     51     while(l < r)
     52     {
     53         mid = (l + r) >> 1;
     54         if(q1[mid] > x) r = mid - 1;
     55         else if(q1[mid] < x) l = mid + 1;
     56         else return mid;
     57     }
     58     if(q1[l] != x) return 0;
     59     else return l;
     60 }
     61 
     62 inline int half2(int x)
     63 {
     64     int l = 1, r = cnt2, mid; 
     65     while(l < r)
     66     {
     67         mid = (l + r) >> 1;
     68         if(q2[mid] > x) r = mid - 1;
     69         else if(q2[mid] < x) l = mid + 1;
     70         else return mid;
     71     }
     72     if(q2[l] != x) return 0;
     73     else return l;
     74 }
     75 
     76 void link(int x)
     77 {
     78     if(d[x] > 0) add(ss, x, d[x], 0);
     79     else if(d[x] < 0) add(x, tt, -d[x], 0);
     80 }
     81 
     82 #define c c_
     83 #define d d_
     84 
     85 void get_lim()
     86 {
     87     int opt, a, b;
     88     for(R i = 1; i <= m; i ++)
     89     {
     90         opt = read(), a = read(), b = read();
     91         if(!a) continue;
     92         if(opt == 1)//x 的限制
     93         {
     94             a = half1(a);
     95             int c = (num1[a] + b) / 2, d = (num1[a] - b + 1) / 2;
     96             if(d > c) {puts("-1"); exit(0);}//,...这里需要判断
     97             upmin(lim1_x[a], c), upmax(lim1_y[a], d), vis1[a] = true;
     98         }
     99         else
    100         {
    101             a = half2(a);
    102             int c = (num2[a] + b) / 2, d = (num2[a] - b + 1) / 2;
    103             if(d > c) {puts("-1"); exit(0);}            
    104             upmin(lim2_x[a], c), upmax(lim2_y[a], d), vis2[a] = true;
    105         }
    106     }
    107 }
    108 
    109 void pre()
    110 {
    111     n = read(), m = read(), red = read(), blue = read();
    112     s = n + m + 1, t = s + 1, ss = t + 1, tt = ss + 1;
    113     memset(lim1_x, 127, sizeof(lim1_x));
    114     memset(lim2_x, 127, sizeof(lim2_x));
    115     for(R i = 1; i <= n; i ++) 
    116         q1[++top1] = p[i].x = read(), q2[++top2] = p[i].y = read();
    117     sort(q1 + 1, q1 + top1 + 1);
    118     sort(q2 + 1, q2 + top2 + 1);
    119     for(R i = 1; i <= top1; i ++)
    120         if(q1[i] != q1[i + 1]) q1[++cnt1] = q1[i];
    121     for(R i = 1; i <= top2; i ++)
    122         if(q2[i] != q2[i + 1]) q2[++cnt2] = q2[i];
    123     g = cnt1, ff = tot + 1;
    124     for(R i = 1; i <= n; i ++)
    125     {
    126         p[i].x = half1(p[i].x), p[i].y = half2(p[i].y);
    127         add(p[i].x, p[i].y + g, 1, 0);
    128         ++num1[p[i].x], ++num2[p[i].y];
    129     }
    130     ww = tot;
    131     get_lim();
    132     for(R i = 1; i <= cnt1; i ++)
    133         if(vis1[i]) add(s, i, lim1_x[i], lim1_y[i]);
    134     for(R i = 1; i <= cnt2; i ++)
    135         if(vis2[i]) add(i + g, t, lim2_x[i], lim2_y[i]);
    136     for(R i = 1; i <= n; i ++)
    137     {
    138         if(!vis1[p[i].x])
    139             vis1[p[i].x] = true, add(s, p[i].x, inf, 0);
    140         if(!vis2[p[i].y])
    141             vis2[p[i].y] = true, add(p[i].y + g, t, inf, 0);
    142     }
    143     add(t, s, inf, 0);
    144     link(s), link(t);
    145     for(R i = 1; i < s; i ++) link(i); 
    146 }
    147 #undef c
    148 #undef d
    149 
    150 void bfs()
    151 {
    152     int x, now, k = flag ? t : tt;
    153     if(flag) memset(have, 0, sizeof(have));
    154     if(flag) memset(c, 0, sizeof(c));
    155     head = tail = 0;
    156     q[++tail] = k, c[k] = 1, have[1] = 1;
    157     while(head < tail)
    158     {
    159         x = q[++head];
    160         for(R i = Head[x]; i; i = Next[i])
    161         {
    162             now = date[i];
    163             if(flag && (now == ss || now == tt)) continue;
    164             if(!c[now]/* && haveflow[i ^ 1]*/)
    165             {
    166                 c[now] = c[x] + 1;
    167                 q[++tail] = now;
    168                 ++ have[c[now]];
    169             }
    170         }
    171     }
    172     memcpy(good, Head, sizeof(Head));
    173 }    
    174 
    175 void aru()
    176 {
    177     int k = flag ? s : ss;
    178     while(x != k)
    179     {
    180         //if(flag) printf("%d ---> %d
    ", x, date[last[x] ^ 1]);
    181         haveflow[last[x]] -= addflow;
    182         haveflow[last[x] ^ 1] += addflow;
    183         x = date[last[x] ^ 1];
    184     }
    185     //printf("
    
    ");
    186     if(flag) ans += addflow;
    187     else got += addflow;
    188 }
    189 
    190 void isap()
    191 {
    192     int now; bool done;int k = flag ? t : tt, kk = flag ? s : ss;
    193     addflow = inf, x = kk;
    194     while(c[kk] != k + 10)
    195     {
    196         if(x == k) aru(), addflow = inf;
    197         done = false;
    198         for(R i = good[x]; i; i = Next[i])
    199         {
    200             now = date[i];
    201             if(flag && (now == ss || now == tt)) continue;
    202             if(c[now] == c[x] - 1 && haveflow[i])
    203             {
    204                 upmin(addflow, haveflow[i]);
    205                 good[x] = i, last[now] = i;
    206                 x = now, done = true;
    207                 break;
    208             }
    209         }
    210         if(!done)
    211         {
    212             int go = k + 9;
    213             for(R i = Head[x]; i; i = Next[i])
    214             {
    215                 now = date[i];
    216                 if(flag && (now == ss || now == tt)) continue;
    217                 if(haveflow[i] && c[now]) upmin(go, c[now]);
    218             }
    219             if(!(-- have[c[x]])) break;
    220             ++have[c[x] = go + 1];
    221             good[x] = Head[x];
    222             if(x != kk) x = date[last[x] ^ 1];
    223         }
    224     }
    225 }
    226 
    227 void write(bool k)
    228 {
    229     if(k)
    230     {
    231         if(red < blue) putchar('r');
    232         else putchar('b');
    233     }
    234     else
    235     {
    236         if(red > blue) putchar('r');
    237         else putchar('b');
    238     }
    239 }
    240 
    241 void find()
    242 {
    243     for(R i = ff; i <= ww; i += 2) write(haveflow[i ^ 1]);
    244     printf("
    ");
    245 }
    246 
    247 void work()
    248 {
    249     LL k = min(red, blue), kk = max(red, blue);
    250     flag = true;
    251     if(got != must) {puts("-1"); return ;}
    252     bfs();
    253     isap();
    254     ans = k * ans + kk * (n - ans);
    255     printf("%lld
    ", ans);
    256     find();
    257 }
    258 
    259 int main()
    260 {
    261     freopen("in.in", "r", stdin);
    262     pre();
    263     bfs();
    264     isap();
    265     work();
    266     fclose(stdin);
    267     return 0;
    268 }
    View Code
  • 相关阅读:
    Gridview常用操作
    在DataGridView列中嵌入ComboBox(vb.net版)【原创】
    使用net创建Access存储过程
    C博客作业00我的第一篇博客 1911
    C博客作业01分支、顺序结构 1911
    Lazy load image for listview and beging separate thread
    Android Send Email
    MySQL修复表数据
    Insertion and Deletion of Calendar Events
    TechCrunch:移动社交应用开创社交网络新格局
  • 原文地址:https://www.cnblogs.com/ww3113306/p/9688790.html
Copyright © 2020-2023  润新知