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 310 1 225 2 35 6 7

Sample Output

17

 //

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=55010;
const int M=950000;
const int inf=(1<<28);
int head[N];
struct Edge
{
    int v,next,w;
} edge[M];
int cnt,n,s,t;//n从0开始  0->n-1
void addedge(int u,int v,int w)
{
    edge[cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt++;
    edge[cnt].v=u;
    edge[cnt].w=0;
    edge[cnt].next=head[v];
    head[v]=cnt++;
}
int sap()
{
    int pre[N],cur[N],dis[N],gap[N];
    int flow=0,aug=inf,u;
    bool flag;
    for(int i=0; i<n; i++)
    {
        cur[i]=head[i];
        gap[i]=dis[i]=0;
    }
    gap[s]=n;
    u=pre[s]=s;
    while(dis[s]<n)
    {
        flag=0;
        for(int &j=cur[u]; j!=-1; j=edge[j].next)
        {
            int v=edge[j].v;
            if(edge[j].w>0&&dis[u]==dis[v]+1)
            {
                flag=1;
                if(edge[j].w<aug) aug=edge[j].w;
                pre[v]=u;
                u=v;
                if(u==t)
                {
                    flow+=aug;
                    while(u!=s)
                    {
                        u=pre[u];
                        edge[cur[u]].w-=aug;
                        edge[cur[u]^1].w+=aug;
                    }
                    aug=inf;
                }
                break;
            }
        }
        if(flag) continue;
        int mindis=n;
        for(int j=head[u]; j!=-1; j=edge[j].next)
        {
            int v=edge[j].v;
            if(edge[j].w>0&&dis[v]<mindis)
            {
                mindis=dis[v];
                cur[u]=j;
            }
        }
        if((--gap[dis[u]])==0)
            break;
        gap[dis[u]=mindis+1]++;
        u=pre[u];
    }
    return flow;
}

//初始化  cnt=0;memset(head,-1,sizeof(head));

int vis[N],a[N],ln;
void dfs(int u)
{
    vis[u]=1;
    a[ln++]=u;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        if(vis[edge[i].v]||edge[i].w==0) continue;
        dfs(edge[i].v);
    }
}
int main()
{
    int m,p;
    while(scanf("%d%d",&m,&p)==2)
    {
        n=m+p+2;
        s=0,t=n-1;
        cnt=0;
        memset(head,-1,sizeof(head));
        int sum=0;
        for(int i=1;i<=m;i++)
        {
            int val;scanf("%d",&val);
            sum+=val;
            addedge(s,i,val);
            int x;
            while(1)
            {
                scanf("%d",&x);
                addedge(i,m+x,inf);
                char ch=getchar();
                if(ch=='\n') break;
            }
        }
        for(int i=1;i<=p;i++)
        {
            int cost;scanf("%d",&cost);
            addedge(m+i,t,cost);
        }
        int mc=sap();
        printf("%d\n",sum-mc);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值