题目描述
W 教授正在为国家航天中心计划一系列的太空飞行。每次太空飞行可进行一系列商业性实验而获取利润。现已确定了一个可供选择的实验集合 E={E1,E2,⋯,Em},和进行这些实验需要使用的全部仪器的集合 I={I1,I2,⋯,In}。实验 Ej 需要用到的仪器是 I 的子集 Rj⊆I。
配置仪器 Ik 的费用为 ck 美元。实验 Ej 的赞助商已同意为该实验结果支付 pj 美元。W 教授的任务是找出一个有效算法,确定在一次太空飞行中要进行哪些实验并因此而配置哪些仪器才能使太空飞行的净收益最大。这里净收益是指进行实验所获得的全部收入与配置仪器的全部费用的差额。
对于给定的实验和仪器配置情况,编程找出净收益最大的试验计划。
输入格式第 1 行有 2 个正整数 m 和 n。m 是实验数,n 是仪器数。接下来的 m 行,每行是一个实验的有关数据。第一个数赞助商同意支付该实验的费用;接着是该实验需要用到的若干仪器的编号。最后一行的 n 个数是配置每个仪器的费用。
输出格式
第 1 行是实验编号,第 2 行是仪器编号,最后一行是净收益。
样例输入
2 3
10 1 2
25 2 3
5 6 7
样例输出
1 2
1 2 3
17
源点与所有试验建边容量为支付的钱,所有器材与汇点建边,容量为个器材的价格,最终最大流为所用器材的价格之和,那么答案就是全部收入-最大流。
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;
const int maxm = 100005;
const int maxn = 55;
const int INF = 1e9 + 7;
struct node
{
int v, flow, next;
}edge[maxm];
int n, m, s, t, cnt;
int head[maxm], vis[maxm], dis[maxm], cur[maxm];
void init()
{
cnt = 0, s = 0, t = n + m + 1;
memset(head, -1, sizeof(head));
}
void add(int u, int v, int w)
{
edge[cnt].v = v, edge[cnt].flow = w, edge[cnt].next = head[u], head[u] = cnt++;
edge[cnt].v = u, edge[cnt].flow = 0, edge[cnt].next = head[v], head[v] = cnt++;
}
int bfs()
{
queue<int>q;
memset(dis, -1, sizeof(dis));
memset(vis, 0, sizeof(vis));
dis[s] = 0;
q.push(s);
while (!q.empty())
{
int u = q.front();q.pop();
for (int i = head[u];i != -1;i = edge[i].next)
{
int v = edge[i].v;
if (dis[v] == -1 && edge[i].flow)
{
vis[v] = 1;
dis[v] = dis[u] + 1;
q.push(v);
}
}
}
if (dis[t] == -1) return 0;
return 1;
}
int dfs(int u, int flow)
{
if (u == t) return flow;
for (int i = cur[u];i != -1;i = edge[i].next)
{
int v = edge[i].v;
if (dis[v] == dis[u] + 1 && edge[i].flow)
{
int d = dfs(v, min(edge[i].flow, flow));
if (d > 0)
{
edge[i].flow -= d, edge[i ^ 1].flow += d;
return d;
}
}
}
return 0;
}
int dinic()
{
int ans = 0, d;
while (bfs())
{
for (int i = 0;i <= t;i++)
cur[i] = head[i];
while (d = dfs(s, INF))
ans += d;
}
return ans;
}
int main()
{
int i, j, k, x, sum = 0, ans, cnt, flag;
char c;
scanf("%d%d", &n, &m);
init();
for (i = 1;i <= n;i++)
{
scanf("%d", &k);
add(s, i, k), sum += k;
for (;;)
{
while ((c = getchar()) == ' '); ungetc(c, stdin);
if (c == 10 || c == 13) break;
scanf("%d", &x);
add(i, x + n, INF);
}
}
for (i = 1;i <= m;i++)
{
scanf("%d", &x);
add(i + n, t, x);
}
ans = sum - dinic();
flag = 0;
for (i = 1;i <= n;i++)
{
if (vis[i])
{
if (!flag) printf("%d", i), flag = 1;
else printf(" %d", i);
}
}
printf("\n");
flag = 0;
for (i = 1;i <= m;i++)
{
if (vis[i + n])
{
if (!flag) printf("%d", i), flag = 1;
else printf(" %d", i);
}
}
printf("\n%d\n", ans);
return 0;
}