【網絡流】太空飛行計畫

Description
W 教授正在为国家航天中心计划一系列的太空飞行。每次太空飞行可进行一系列商业性实验而获取利润。现已确定了一个可供选择的实验集合E={E1,E2,…,Em},和进行这些实验需要使用的全部仪器的集合I={I1, I2,…In}。实验Ej需要用到的仪器是I的子集Rj ÍI。

配置仪器Ik的费用为ck美元。实验Ej的赞助商已同意为该实验结果支付pj美元。W教授的任务是找出一个有效算法,确定在一次太空飞行中要进行哪些实验并因此而配置哪些仪器才能使太空飞行的净收益最大。这里净收益是指进行实验所获得的全部收入与配置仪器的全部

费用的差额。

对于给定的实验和仪器配置情况,编程找出净收益最大的试验计划。

Input
文件第1行有2 个正整数m和n。m是实验数,n是仪器数。接下来的m 行,每行是一个实验的有关数据。第一个数赞助商同意支付该实验的费用;接着是该实验需要用到的若干仪器的编号。最后一行的n个数是配置每个仪器的费用。

Output
 第1行是实验编号;第2行是仪器编号;最后一行是净收益

Sample Input
2 3                      
10 1 2                
25 2 3                    
5 6 7

Sample Output
1 2
1 2 3
1 7

這道題是最大獲利的翻版……

只需將最後的方案輸出即可。

Accode:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <bitset>
using std::cin;
using std::bitset;

const char fi[] = "shut.in";
const char fo[] = "shut.out";
const int maxN = 110;
const int MAX = 0x3fffff00;
const int MIN = -MAX;

int map[maxN][maxN];
int f[maxN][maxN];
int d[maxN], cnt[maxN];
int t[maxN], ele[maxN][maxN];
bitset <maxN> expr, instr;
int N, M, n, ans, c;

  void init_file()
  {
    freopen(fi, "r", stdin);
    freopen(fo, "w", stdout);
    std::ios::sync_with_stdio(false);
  }

  void readdata()
  {
    cin >> M >> N;
    n = M + N + 2;
    for (int i = 2; i < M + 2; ++i)
    {
      cin >> c;
      ans += c;
      map[1][i] = f[1][i] = c;
      while (1)
      {
        if (cin.peek() == '\n') break;
        cin >> c;
        ele[i - 1][++t[i - 1]] = c;
        map[i][c + M + 1] = f[i][c + M + 1] = MAX;
      }
    }
    for (int i = M + 2; i < n; ++i)
    {
      cin >> c;
      map[i][n] = f[i][n] = c;
    }
  }

  int Sap(int u, int Lim)
  {
    if (u == n) return Lim;
    int tmp = 0;
    for (int v = 1; v < n + 1; ++v)
     if (f[u][v] > 0 && d[u] == d[v] + 1)
      {
        int k = Sap(v, std::min(Lim
          - tmp, f[u][v]));
        if (k <= 0) continue;
        f[u][v] -= k;
        f[v][u] += k;
        if ((tmp += k) == Lim) return tmp;
      }
    if (d[1] >= n) return tmp;
    if ((--cnt[d[u]]) <= 0) d[1] = n;
    ++cnt[++d[u]];
    return tmp;
  }

  void work()
  {
    cnt[0] = n;
    while (d[1] < n) ans -= Sap(1, MAX);
    if (!ans) {printf("0"); return; }
    expr.set();
    instr.set();
    int k;
    for (k = 0; k < n; ++k)
      if (!cnt[k]) break;
	//找到斷點。
    for (int i = 2; i < n; ++i)
     if (d[i] < k)
      {
        if (i > M + 1) instr.reset(i - M - 1);
        else expr.reset(i - 1);
      }
	//在斷點以下的點不被選中。
    for (int i = 1; i < M + 1; ++i)
      if (expr.test(i)) printf("%d ", i);
    printf("\n");
    for (int i = 1; i < N + 1; ++i)
      if (instr.test(i)) printf("%d ", i);
    printf("\n%d", ans);
  }

int main()
{
  init_file();
  readdata();
  work();
  exit(0);
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值