[2019杭电多校第二场][hdu6598]Harmonious Army(最小割)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6598

题意是说一个军队有n人,你可以给他们每个人安排战士或者法师的职业,有m对人有组合技,组合技的信息是A,B,C,代表如果这两个人是两个战士,则组合技威力为A,一个战士一个法师,威力为B,其中B=A/4+C/3,两个法师,威力为C,求最大的威力。

很网络流的题目,那就流呗XD

先考虑如果每个人可以选择两个职业,则威力为$sum=\sum_{i=1}^{n}(a[i]+b[i]+c[i])$

如果不能选择两个职业,则可以看成选择两个职业的答案减去网络中的最小割。

则我们向着最小割的方向思考。

然后我们先考虑连通性,即所有点连战士(看成源点)和法师(看成汇点),并且有关系的点相互连接。

然后看下面的图(s为源点,t为汇点,x,y为一对关系)

然后考虑权值:

如果x选择战士,y选择战士,则a+b=B+C(割掉B,C的威力)

如果x选择法师,y法师战士,则c+d=B+A(割掉A,B的威力)

如果x选择战士,y选择法师,则a+e+d=A+C(割掉A,C的威力)

如果x选择法师,y选择战士,则b+e+c=A+C(割掉A,C的威力)

然后可以得到一组解a=b=(A+B)/2,c=d=(C+B)/2,e=(A+C)/2-B。

然后就可以愉快的建图。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<string>
 7 #include<queue>
 8 using namespace std;
 9 typedef long long ll;
10 const int maxn = 2e5 + 10;
11 const ll inf = 1e18;
12 struct node {
13     int e, next;
14     double w;
15 }edge[maxn];
16 int head[maxn], len;
17 int d[maxn];
18 void init() {
19     memset(head, -1, sizeof(head));
20     len = 0;
21 }
22 void add(int s, int e, double  w) {
23     edge[len].e = e;
24     edge[len].w = w;
25     edge[len].next = head[s];
26     head[s] = len++;
27 }
28 bool bfs(int s, int e) {
29     queue<int>q;
30     memset(d, 0, sizeof(d));
31     d[s] = 1;
32     q.push(s);
33     while (!q.empty()) {
34         int x = q.front(); q.pop();
35         for (int i = head[x]; i != -1; i = edge[i].next) {
36             int y = edge[i].e;
37             if (edge[i].w && !d[y]) {
38                 d[y] = d[x] + 1;
39                 q.push(y);
40             }
41         }
42     }
43     return d[e];
44 }
45 double dfs(int x, int e, double limit) {
46     if (x == e)
47         return limit;
48     double add, ans = 0;
49     for (int i = head[x]; i != -1; i = edge[i].next) {
50         int y = edge[i].e;
51         if (d[y] == d[x] + 1 && edge[i].w) {
52             add = dfs(y, e, min(edge[i].w, limit));
53             edge[i].w -= add;
54             edge[i ^ 1].w += add;
55             ans += add;
56             limit -= add;
57             if (!limit)
58                 break;
59         }
60     }
61     if (!ans)
62         d[x] = -1;
63     return ans;
64 }
65 double dinic(int s, int e) {
66     double ans = 0;
67     while (bfs(s, e))
68         ans += dfs(s, e, inf);
69     return ans;
70 }
71 int main() {
72     int n, m;
73     while (scanf("%d%d", &n, &m) != EOF) {
74         init();
75         int s = n + 1, t = n + 2;
76         ll sum = 0;
77         for (int i = 1; i <= m; i++) {
78             ll x, y;
79             double a, b, c;
80             scanf("%lld%lld%lf%lf%lf", &x, &y, &a, &b, &c);
81             add(s, x, (a + b) / 2);
82             add(x, s, 0);
83             add(s, y, (a + b) / 2);
84             add(y, s, 0);
85             add(x, t, (b + c) / 2);
86             add(t, x, 0);
87             add(y, t, (b + c) / 2);
88             add(t, y, 0);
89             add(x, y, -b + (a + c) / 2);
90             add(y, x, 0);
91             add(y, x, -b + (a + c) / 2);
92             add(x, y, 0);
93             sum += a + b + c;
94         }
95         ll ans = round(sum - dinic(s, t));
96         printf("%lld\n", ans);
97     }
98 }

 

posted @ 2019-08-09 17:27  祈梦生  阅读(289)  评论(0编辑  收藏  举报