Loading [MathJax]/extensions/tex2jax.js

「Fortuna OJ」4682「GDOI2017模拟8.11」生物学家

主要思路

这道题原题解作者的思路非常的清晰。我来阐述一下。

首先思考答案的意义,一定是总的权值和减去:

  • 变性花费
  • 不要的赞助费
  • 喝茶费用

我们可以用上面这三个元素组一个网络流,计算最小割使答案最大。

考虑将源点连入雌性,雄性连入雄性,流上限就是变性花费:如果将这种边割掉,那么就是不需要进行变性。考虑朋友的边,如果倾向于变雌性,源点连入,向所有的对应编号连边;如果雄性,连入汇点,所有对应编号的向该朋友连边。

代码

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// FOJ4682.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1e5 + 200, INF = 0x3f3f3f3f;
int head[MAX_N], current, st, ed, dep[MAX_N], cur[MAX_N];
int n, m, g, sex[MAX_N];
struct edge
{
int to, nxt, weight;
} edges[MAX_N << 2];
void addpath(int src, int dst, int weight)
{
edges[current].to = dst, edges[current].nxt = head[src];
edges[current].weight = weight, head[src] = current++;
}
void addtube(int src, int dst, int weight)
{
addpath(src, dst, weight);
addpath(dst, src, 0);
}
bool bfs()
{
memset(dep, 0, sizeof(dep));
queue<int> q;
q.push(st), dep[st] = 1;
while (!q.empty())
{
int u = q.front();
q.pop();
for (int i = head[u]; i != -1; i = edges[i].nxt)
if (edges[i].weight > 0 && dep[edges[i].to] == 0)
q.push(edges[i].to), dep[edges[i].to] = dep[u] + 1;
}
return dep[ed] != 0;
}
int dfs(int u, int flow)
{
if (u == ed || flow == 0)
return flow;
for (int &i = cur[u]; i != -1; i = edges[i].nxt)
if (edges[i].weight > 0 && dep[edges[i].to] == dep[u] + 1)
if (int di = dfs(edges[i].to, min(flow, edges[i].weight)))
{
edges[i].weight -= di, edges[i ^ 1].weight += di;
return di;
}
return 0;
}
int dinic()
{
int ans = 0;
while (bfs())
{
memcpy(cur, head, sizeof(head));
while (int di = dfs(st, INF))
ans += di;
}
return ans;
}
int main()
{
memset(head, -1, sizeof(head));
scanf("%d%d%d", &n, &m, &g);
st = n + m + 1, ed = st + 1;
for (int i = 1; i <= n; i++)
scanf("%d", &sex[i]);
for (int i = 1, ci; i <= n; i++)
{
scanf("%d", &ci);
if (sex[i] == 0)
addtube(st, i, ci);
else
addtube(i, ed, ci);
}
int answer = 0;
for (int i = 1, wi, certainSex, ki, id, isFriend; i <= m; i++)
{
scanf("%d%d%d", &certainSex, &wi, &ki);
answer += wi;
while (ki--)
{
scanf("%d", &id);
if (certainSex == 0)
addtube(i + n, id, INF);
else
addtube(id, i + n, INF);
}
scanf("%d", &isFriend);
if (certainSex == 0)
addtube(st, i + n, wi + ((isFriend) ? g : 0));
else
addtube(i + n, ed, wi + ((isFriend) ? g : 0));
}
answer -= dinic();
printf("%d", answer);
return 0;
}
// FOJ4682.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 1e5 + 200, INF = 0x3f3f3f3f; int head[MAX_N], current, st, ed, dep[MAX_N], cur[MAX_N]; int n, m, g, sex[MAX_N]; struct edge { int to, nxt, weight; } edges[MAX_N << 2]; void addpath(int src, int dst, int weight) { edges[current].to = dst, edges[current].nxt = head[src]; edges[current].weight = weight, head[src] = current++; } void addtube(int src, int dst, int weight) { addpath(src, dst, weight); addpath(dst, src, 0); } bool bfs() { memset(dep, 0, sizeof(dep)); queue<int> q; q.push(st), dep[st] = 1; while (!q.empty()) { int u = q.front(); q.pop(); for (int i = head[u]; i != -1; i = edges[i].nxt) if (edges[i].weight > 0 && dep[edges[i].to] == 0) q.push(edges[i].to), dep[edges[i].to] = dep[u] + 1; } return dep[ed] != 0; } int dfs(int u, int flow) { if (u == ed || flow == 0) return flow; for (int &i = cur[u]; i != -1; i = edges[i].nxt) if (edges[i].weight > 0 && dep[edges[i].to] == dep[u] + 1) if (int di = dfs(edges[i].to, min(flow, edges[i].weight))) { edges[i].weight -= di, edges[i ^ 1].weight += di; return di; } return 0; } int dinic() { int ans = 0; while (bfs()) { memcpy(cur, head, sizeof(head)); while (int di = dfs(st, INF)) ans += di; } return ans; } int main() { memset(head, -1, sizeof(head)); scanf("%d%d%d", &n, &m, &g); st = n + m + 1, ed = st + 1; for (int i = 1; i <= n; i++) scanf("%d", &sex[i]); for (int i = 1, ci; i <= n; i++) { scanf("%d", &ci); if (sex[i] == 0) addtube(st, i, ci); else addtube(i, ed, ci); } int answer = 0; for (int i = 1, wi, certainSex, ki, id, isFriend; i <= m; i++) { scanf("%d%d%d", &certainSex, &wi, &ki); answer += wi; while (ki--) { scanf("%d", &id); if (certainSex == 0) addtube(i + n, id, INF); else addtube(id, i + n, INF); } scanf("%d", &isFriend); if (certainSex == 0) addtube(st, i + n, wi + ((isFriend) ? g : 0)); else addtube(i + n, ed, wi + ((isFriend) ? g : 0)); } answer -= dinic(); printf("%d", answer); return 0; }
// FOJ4682.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 1e5 + 200, INF = 0x3f3f3f3f;

int head[MAX_N], current, st, ed, dep[MAX_N], cur[MAX_N];
int n, m, g, sex[MAX_N];

struct edge
{
    int to, nxt, weight;
} edges[MAX_N << 2];

void addpath(int src, int dst, int weight)
{
    edges[current].to = dst, edges[current].nxt = head[src];
    edges[current].weight = weight, head[src] = current++;
}

void addtube(int src, int dst, int weight)
{
    addpath(src, dst, weight);
    addpath(dst, src, 0);
}

bool bfs()
{
    memset(dep, 0, sizeof(dep));
    queue<int> q;
    q.push(st), dep[st] = 1;
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        for (int i = head[u]; i != -1; i = edges[i].nxt)
            if (edges[i].weight > 0 && dep[edges[i].to] == 0)
                q.push(edges[i].to), dep[edges[i].to] = dep[u] + 1;
    }
    return dep[ed] != 0;
}

int dfs(int u, int flow)
{
    if (u == ed || flow == 0)
        return flow;
    for (int &i = cur[u]; i != -1; i = edges[i].nxt)
        if (edges[i].weight > 0 && dep[edges[i].to] == dep[u] + 1)
            if (int di = dfs(edges[i].to, min(flow, edges[i].weight)))
            {
                edges[i].weight -= di, edges[i ^ 1].weight += di;
                return di;
            }
    return 0;
}

int dinic()
{
    int ans = 0;
    while (bfs())
    {
        memcpy(cur, head, sizeof(head));
        while (int di = dfs(st, INF))
            ans += di;
    }
    return ans;
}

int main()
{
    memset(head, -1, sizeof(head));
    scanf("%d%d%d", &n, &m, &g);
    st = n + m + 1, ed = st + 1;
    for (int i = 1; i <= n; i++)
        scanf("%d", &sex[i]);
    for (int i = 1, ci; i <= n; i++)
    {
        scanf("%d", &ci);
        if (sex[i] == 0)
            addtube(st, i, ci);
        else
            addtube(i, ed, ci);
    }
    int answer = 0;
    for (int i = 1, wi, certainSex, ki, id, isFriend; i <= m; i++)
    {
        scanf("%d%d%d", &certainSex, &wi, &ki);
        answer += wi;
        while (ki--)
        {
            scanf("%d", &id);
            if (certainSex == 0)
                addtube(i + n, id, INF);
            else
                addtube(id, i + n, INF);
        }
        scanf("%d", &isFriend);
        if (certainSex == 0)
            addtube(st, i + n, wi + ((isFriend) ? g : 0));
        else
            addtube(i + n, ed, wi + ((isFriend) ? g : 0));
    }
    answer -= dinic();
    printf("%d", answer);
    return 0;
}

 

Leave a Reply

Your email address will not be published. Required fields are marked *