BZOJ 3996 [TJOI 2015] 线性代数 解题报告

首先,我们可以得到:

$$D = \sum_{i=1}^{n}\sum_{j=1}^{n}a_i\times a_j\times b_{i,j} - \sum_{i=1}^{n}a_i\times c_i$$

那么是不是就相当于这样的问题:

有 $n$ 个物品,你可以选择一些物品出来,如果同时选了 $i,j$ 两个物品那么就有 $b_{i,j}$ 的收益,然而每一个物品都有一个代价 $c_i$,求最大收益。

这是经典的最小割模型:

  • 连边 $S\to Dot(i,j)$,流量为 $b_{i,j}$。
  • 连边 $Dot(i,j)\to i$ 以及 $Dot(i,j)\to j$,流量为 $\infty$。
  • 连边 $i\to T$,流量为 $c_i$

设最小割为 $x$,那么答案就是:

$$\sum_{i=1}^{n}\sum_{j=1}^{n}b_{i,j} - x$$

尽管有很多个点,但还是可以跑得很快的。(*^_^*)

 1 #include <cmath>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <iostream>
 5 #include <algorithm>
 6 using namespace std;
 7 typedef long long LL;
 8 #define N 250000 + 500 + 5
 9 #define M 2500000 + 5
10 #define INF 0x7fffffff
11 
12 int n, S, T, cnt, tot = 1;
13 int Head[N], q[N], Dfn[N];
14 LL ans;
15 
16 struct Edge
17 {
18     int next, node, flow;
19 }h[M];
20 
21 inline void addedge(int u, int v, int fl)
22 {
23     h[++ tot].next = Head[u], Head[u] = tot;
24     h[tot].node = v, h[tot].flow = fl;
25     h[++ tot].next = Head[v], Head[v] = tot;
26     h[tot].node = u, h[tot].flow = 0;
27 }
28 
29 inline bool BFS()
30 {
31     for (int i = S; i <= T; i ++)
32         Dfn[i] = 0;
33     int l = 1, r = 1;
34     q[1] = S, Dfn[S] = 1;
35     while (l <= r)
36     {
37         int z = q[l ++];
38         for (int i = Head[z]; i; i = h[i].next)
39         {
40             int d = h[i].node, p = h[i].flow;
41             if (!p || Dfn[d]) continue ;
42             Dfn[d] = Dfn[z] + 1;
43             q[++ r] = d;
44             if (d == T) return 1;
45         }
46     }
47     return 0;
48 }
49 
50 inline int dinic(int z, int inflow)
51 {
52     if (z == T) return inflow;
53     int ret = inflow, flow;
54     for (int i = Head[z]; i; i = h[i].next)
55     {
56         int d = h[i].node, p = h[i].flow;
57         if (Dfn[d] != Dfn[z] + 1 || !p) continue ;
58         flow = dinic(d, min(p, ret));
59         ret -= flow;
60         h[i].flow -= flow, h[i ^ 1].flow += flow;
61         if (!ret) return inflow;
62     }
63     if (ret == inflow) Dfn[z] = -1;
64     return inflow - ret;
65 }
66 
67 int main()
68 {
69     #ifndef ONLINE_JUDGE
70         freopen("3996.in", "r", stdin);
71         freopen("3996.out", "w", stdout);
72     #endif
73     
74     scanf("%d", &n);
75     S = 0, T = n + n * n + 1, cnt = n;
76     for (int i = 1; i <= n; i ++)
77         for (int j = 1, w; j <= n; j ++)
78         {
79             scanf("%d", &w);
80             addedge(S, ++ cnt, w);
81             addedge(cnt, i, INF);
82             addedge(cnt, j, INF);
83             ans += w;
84         }
85     for (int i = 1, w; i <= n; i ++)
86     {
87         scanf("%d", &w);
88         addedge(i, T, w);
89     }
90     while (BFS())
91         ans -= dinic(S, INF);
92     printf("%lld\n", ans);
93     
94     #ifndef ONLINE_JUDGE
95         fclose(stdin);
96         fclose(stdout);
97     #endif
98     return 0;
99 }
3996_Gromah

 

posted @ 2015-04-23 20:03  Gromah  阅读(932)  评论(0编辑  收藏  举报