• POJ 3308, ZOJ 2874


    题意:

    R×C的网格中有N个点,选取其中的若干行和若干列将这些点全部覆盖(选取一行/列可以覆盖该行/列的所有点,要求每个点至少被覆盖一次)。

    选取第i行的代价为r[i],选取第i列的代价为c[i],求代价乘积的最小值。

    R, C, N≤50,r[i], c[i]均为≥1.0的正实数

    转化成最小割问题。建图方法如下:

    (1)设立源点S和汇点T,对于每行、每列分别建立一个对应的节点;

    (2)从源点出发,向每行连一条边,权值为r[i]的对数(底数自拟)。转化成对数可以将乘积最优问题转化为和最优。

    (3)从每列出发,分别向汇点连一条边,权值为c[i]的对数;

    (4)对于网格中的每一个点,设它在第x行第y列,在图中从第x行向第y列连一条边,权值为+∞。

    注意:由于诡异的精度误差,inf的值取太大可能会导致WA!

    代码如下:(前50行是个比较通用的大型边表模板,在赛场上如果有多道图论题的话可以省点时间……吧(这玩意儿会有卵用么))

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 #include <queue>
      5 #include <cmath>
      6 
      7 #define FILL(a, c) memset(a, c, sizeof(a))
      8 
      9 template <int V, int E> //V为最大节点数,E为最大边数
     10 struct EList
     11 {
     12     struct Edge { int to; double flow; };
     13     struct Node: Edge
     14     {
     15         int next;
     16         void assign(int t, int n, double f) { this->to = t; next = n; this->flow = f; }
     17     };
     18     struct Iter //迭代从节点v出发的所有边
     19     {
     20         EList *par;
     21         int e;
     22         Iter& operator ++ () { e = par->elist[e].next; return *this; }
     23         bool operator != (const Iter& rhs) const { return e != rhs.e; }
     24         //operator*返回的是引用类型
     25         Edge& operator * () const { return par->elist[e]; } //只保留基类部分,不含next
     26         Edge* operator -> () const { return par->elist + e; }
     27         //(适用于网络流等问题)返回反向边
     28         Edge& inv() const { return par->elist[e ^ 1]; }
     29     };
     30     struct View //用于遍历从某个节点出发的所有边的视图,配合C++11的range-based for使用
     31     {
     32         EList *par;
     33         int v;
     34         Iter begin() const { return { par, par->head[v] }; }
     35         Iter end() const { return { par, -1 }; } //用-1表示结束
     36     };
     37 
     38     Node elist[E];
     39     int head[V];
     40     int ecnt;
     41 
     42     void init()
     43     {
     44         FILL(head, -1); //用-1表示结束
     45         ecnt = 0;
     46     }
     47     void add(int u, int v, double f)
     48     {
     49         elist[ecnt].assign(v, head[u], f);
     50         head[u] = ecnt++;
     51         elist[ecnt].assign(u, head[v], 0.0);
     52         head[v] = ecnt++;
     53     }
     54     //返回从v节点出发的所有边的视图
     55     View view(int v) { return { this, v }; } //如果编译错误,试着将this指针const_cast一下
     56     //迭代从v出发的所有边的另一种方式,对于网络流等需要访问反向边的场合,View就不太适合了
     57     Iter begin(int v) { return { this, head[v] }; }
     58     Iter end(int v = -1) { return { this, -1 }; }
     59 };
     60 
     61 int R, C, N, S, T;
     62 EList<110, 123456> elist;
     63 
     64 void input()
     65 {
     66     scanf("%d%d%d", &R, &C, &N);
     67     elist.init();
     68     S = 0;
     69     T = R + C + 1;
     70 
     71     for (int i = 1; i <= R; i++)
     72     {
     73         double v;
     74         scanf("%lf", &v);
     75         elist.add(S, i, log2(v));
     76     }
     77     for (int i = 1; i <= C; i++)
     78     {
     79         double v;
     80         scanf("%lf", &v);
     81         elist.add(i + R, T, log2(v));
     82     }
     83 
     84     for (int u, v, i = 1; i <= N; i++)
     85     {
     86         scanf("%d%d", &u, &v);
     87         elist.add(u, R + v, 1e50);
     88     }
     89 }
     90 
     91 int layer[110];
     92 std::queue<int> que;
     93 
     94 bool bfs()
     95 {
     96     FILL(layer, -1);
     97     que.push(S);
     98     layer[S] = 0;
     99 
    100     while (!que.empty())
    101     {
    102         int cur = que.front();
    103         que.pop();
    104 
    105         for (auto& e: elist.view(cur))
    106         {
    107             if (layer[e.to] == -1 && e.flow > 0.0)
    108             {
    109                 layer[e.to] = layer[cur] + 1;
    110                 que.push(e.to);
    111             }
    112         }
    113     }
    114     return layer[T] != -1;
    115 }
    116 
    117 //#include <fmt/format.h>
    118 //using namespace fmt::literals;
    119 
    120 double dfs(int cur, double rem)
    121 {
    122     if (cur == T)
    123         return rem;
    124 
    125     double origRem = rem;
    126     for (auto it = elist.begin(cur); rem > 0.0 && it != elist.end(); ++it)
    127     {
    128         if (layer[it->to] == layer[cur] + 1 && it->flow > 0.0)
    129         {
    130             double n = dfs(it->to, std::min(rem, it->flow));
    131             //fmt::print("cur = {cur}, to = {to}, flow = {flow:.3f}
    ", "cur"_a = cur, "to"_a = it->to, "flow"_a = n);
    132             rem -= n;
    133             it->flow -= n;
    134             it.inv().flow += n;
    135         }
    136     }
    137     return origRem - rem;
    138 }
    139 
    140 double solve()
    141 {
    142     double ans = 0.0;
    143     while (bfs())
    144         ans += dfs(S, 100);
    145     return pow(2.0, ans);
    146 }
    147 
    148 int main()
    149 {
    150     int T;
    151     for (scanf("%d", &T); T; T--)
    152     {
    153         input();
    154         printf("%.4f
    ", solve());
    155     }
    156     return 0;
    157 }
  • 相关阅读:
    JavaScript WebSocket C# SuperSocket.WebSocket 示例
    Nginx 配置
    Temporary Post Used For Theme Detection (272f6d70fb8946f3a568afd3d7b053bd 3bfe001a32de4114a6b44005b770f6d7)
    SpringBoot多数据源事务解决方案
    SpringBoot集成mybatis拦截器修改表名
    点击各个按钮,在执行操作之前出现确认提示框
    incoming change和current change
    Expected Number with value 8, got String with value "8".
    正则只能输入数字遇到的问题
    Antd 4.19 Modal + Form;打开modal时使用setFieldsValue,首次回显正常,第二次无效?
  • 原文地址:https://www.cnblogs.com/Onlynagesha/p/8810568.html
Copyright © 2020-2023  润新知