SOJ 3109 Space flight

Description



W教授正在为国家航天中心计划一系列的太空飞行。每次太空飞行可进行一系列商业性实验而获取利润。
现已确定了一个可供选择的实验集合E={E1,E2,…,Em},和进行这些实验需要使用的全部仪器的集合I={I1,I2,…In}。
实验Ej需要用到的仪器是I的子集RjI。
配置仪器Ik的费用为ck美元。实验Ej的赞助商已同意为该实验结果支付pj美元。
W教授的任务是找出一个有效算法,
确定在一次太空飞行中要进行哪些实验并因此而配置哪些仪器才能使太空飞行的净收益最大。
这里净收益是指进行实验所获得的全部收入与配置仪器的全部费用的差额。
对于给定的实验和仪器配置情况,编程找出净收益最大的试验计划。

Input



输入包含多组测试数据,每组数据第1行有2个正整数m和n。m是实验数,n是仪器数。
接下来的m行,每行是一个实验的有关数据。
第一个数赞助商同意支付该实验的费用;接着是该实验需要用到的若干仪器的编号。
最后一行的n个数是配置每个仪器的费用。
( 1 <= m,n <= 50 )

Output



每组数据输出一行,为净收益。

Sample Input



2 3
10 1 2
25 2 3
5 6 7

Sample Output



17

Source



经典问题

 

与上回那个题目相似

LRJ那本书里面有写到

 

#include<iostream>
#include<cstring>
using namespace std;
const  int MAXN = 2012;
const  int MAXM = 1000000;
const  int INF = 0x7fffffff;
struct   Edge
{
    int   st, ed;
    int   next;
    int   flow;
} edge[MAXM];
int   head[MAXN];
int   value[MAXN];
int   N, M, F, E;
int   src, dest;
int   seq[MAXM], sl;
int   ans = 0;
void   add_edge(int u, int v, int w)
{
    edge[E].flow = w;
    edge[E].st = u;
    edge[E].ed = v;
    edge[E].next = head[u];
    head[u] = E++;

    edge[E].flow = 0;
    edge[E].st = v;
    edge[E].ed = u;
    edge[E].next = head[v];
    head[v] = E++;
}
int   d[MAXN];
bool   dinic_bfs(void)
{
    int   i, j;
    memset(d, -1, sizeof(d));
    int   que[MAXN], rear = 1;
    que[0] = src;
    d[src] = 0;
    for(i = 0; i < rear; i++)
    {
        for(j = head[que[i]]; j != -1; j = edge[j].next)
        {
            if(d[edge[j].ed] == -1 && edge[j].flow > 0)
            {
                d[edge[j].ed] = d[que[i]]+1;
                que[rear++] = edge[j].ed;
                if(edge[j].ed==dest)
                    return true;
            }
        }
    }
    return  false;
}
int   dinic_dfs(void)
{
    int   stk[MAXN], top = 0;
    int   ret = 0, cur, ptr, pre[MAXN], minf, i;
    bool   del[MAXN];
    memset(del, false, sizeof(del));

    stk[top++] = src;
    pre[src] = src;
    cur = src;
    while(top)
    {
        while(cur != dest && top)
        {
            for(i = head[cur]; i != -1; i = edge[i].next)
            {
                if(d[edge[i].ed] == d[cur]+1 && edge[i].flow > 0 && !del[edge[i].ed])
                {
                    stk[top++] = edge[i].ed;
                    cur = edge[i].ed;
                    pre[edge[i].ed] = i;
                    break;
                }
            }
            if(i == -1)
            {
                del[cur] = 1;
                top--;
                if(top) cur = stk[top-1];
            }
        }
        if(cur == dest)
        {
            minf = INF;
            while(cur != src)
            {
                cur = pre[cur];
                if(edge[cur].flow < minf) minf = edge[cur].flow;
                cur = edge[cur].st;
            }
            cur = dest;
            while(cur != src)
            {
                cur = pre[cur];
                edge[cur].flow -= minf;
                edge[cur^1].flow += minf;
                if(edge[cur].flow == 0) ptr = edge[cur].st;
                cur = edge[cur].st;
            }
            while(top > 0&& stk[top-1] != ptr) top--;
            if(top)   cur = stk[top-1];
            ret += minf;
        }
    }
    return   ret;
}
int   Dinic()
{
    int   ret = 0, t;
    while(dinic_bfs())
    {
        t = dinic_dfs();
        if(t) ret += t;
        else  break;
    }
    return ret;

}
int   main()
{
    int n,m;
    int i,j,k,x,y;
    char c;
    while(scanf("%d%d",&m,&n)!=EOF)
    {
        src=0;
        dest=n+m+2;
        E=0;
        memset(head,-1,sizeof(head));
        int sum=0;
        for(i=1; i<=m; i++)
        {
            scanf("%d",&x);
            add_edge(i+n,dest,x);
            sum+=x;
            while(scanf("%d%c",&x,&c))
            {
                add_edge(x,i+n,INF);
                if(c=='/n')
                    break;
            }
        }
        for(i=1; i<=n; i++)
        {
            scanf("%d",&x);
            add_edge(0,i,x);

        }
        printf("%d/n",sum-Dinic());
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值