师范大学の矿山
Time Limit: 1000/2000 MS (C++/Others) Memory Limit: 262144 /524288K (C++/Others)
题目描述 #
师范大学有一座矿山,因为改造江边学生公寓需要花费大量资金,所以现在让你负 责挖矿,你需要根据矿石(以下称石头)的属性来计算它能获得的最大利润。
每一块石头 有一个价值 和挖掘的成本 ,有些石头会阻挡其他石头,比如,如 果石头 被石头 和石头 挡住,那么必须先把石头 和石头 挖出来,才能挖石头 ,当一块石头没有被其他石头阻挡时,它就可以被挖出来。
输入描述 # 第一行一个整数 ,代表石头的数量,石头编号从 到 ,接下来 行描述这些 石头的属性。第 行代表石头 ,首先是两个数 和 代表价值和成本,然后第三 个数 表示石头 阻挡的石头数量,最后是 个数 表示石头 阻挡的那些石头的 编号。
输入保证有合理的挖掘顺序来挖掘每一块石头,所有石头的 之和不会超过500。
输出描述 #1<=N<=200,0<=vi,ci<=200,0<=mi<=N-1
输出一个整数代表挖掘这些石头能获取的最大利润。
输入
5
0 3 2 2 3
1 3 2 4 5
4 8 1 4
5 3 0
9 2 0
输出
2
题解:先把所有能获利 的点都加起来,再建图(从源点到获利的点连边,权值为获利值,把赔钱的点到汇点连边,权值为赔钱数值,如果在挖第i个点之前要先挖第J个点,那么从第i个点到第j个点连边,权值为INF),找最大流,即最大流的值为要选择这些获利点必须要损失的钱,最后把所有获利点的利润加起来然后减去最大流,即为能得到的最大利润。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
const int maxn = 510;
const int maxm = 250010;
int N, NP, NC;
const int inf = 0x3f3f3f3f;
struct Edge
{
int u, v, cap;
Edge() {}
Edge(int u, int v, int cap): u(u), v(v), cap(cap) {}
} es[maxm];
int R, S, T;
vector<int> tab[maxn]; // 边集
int dis[maxn];
int current[maxn];
void addedge(int u, int v, int cap)
{
tab[u].push_back(R);
es[R++] = Edge(u, v, cap); // 正向边
tab[v].push_back(R);
es[R++] = Edge(v, u, 0); // 反向边容量为0
// 正向边下标通过异或就得到反向边下标, 2 ^ 1 == 3 ; 3 ^ 1 == 2
}
int BFS()
{
queue<int> q;
q.push(S);
memset(dis, 0x3f, sizeof(dis));
dis[S] = 0;
while (!q.empty())
{
int h = q.front();
q.pop();
for (int i = 0; i < tab[h].size(); i++)
{
Edge &e = es[tab[h][i]];
if (e.cap > 0 && dis[e.v] == 0x3f3f3f3f)
{
dis[e.v] = dis[h] + 1;
q.push(e.v);
}
}
}
return dis[T] < 0x3f3f3f3f; // 返回是否能够到达汇点
}
int dinic(int x, int maxflow)
{
if (x == T)
return maxflow;
// i = current[x] 当前弧优化
for (int i = current[x]; i < tab[x].size(); i++)
{
current[x] = i;
Edge &e = es[tab[x][i]];
if (dis[e.v] == dis[x] + 1 && e.cap > 0)
{
int flow = dinic(e.v, min(maxflow, e.cap));
if (flow)
{
e.cap -= flow; // 正向边流量降低
es[tab[x][i] ^ 1].cap += flow; // 反向边流量增加
return flow;
}
}
}
return 0; // 找不到增广路 退出
}
int DINIC()
{
int ans = 0;
while (BFS()) // 建立分层图
{
int flow;
memset(current, 0, sizeof(current)); // BFS后应当清空当前弧数组
while (flow = dinic(S, 0x3f3f3f3f)) // 一次BFS可以进行多次增广
ans += flow;
}
return ans;
}
int main()
{
int n,u, v, m, x;
scanf("%d", &n);
R = 0, S = 0, T = n + 1;
int sum = 0;
for (int i = 1; i <= n; ++i)
{
scanf("%d%d%d", &u, &v, &m);
if (u > v)
{
addedge(S, i, u - v); // 土地与源点
sum += (u - v);
}
else
addedge(i, T, v - u); // 土地与汇点
for (int j = 0; j < m; ++j)
{
scanf("%d", &x);
addedge(x, i, inf);
}
}
printf("%d\n", sum - DINIC());
return 0;
}
来源:https://blog.csdn.net/weixin_44502066/article/details/99698212