loj #6001. 「网络流 24 题」太空飞行计划(最大权闭合子图)

#6001. 「网络流 24 题」太空飞行计划

内存限制:256 MiB 时间限制:1000 ms 标准输入输出
题目类型:传统 评测方式:Special Judge
上传者: 匿名
题目描述

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

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

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

输入格式

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

输出格式

第 1 11 行是实验编号,第 2 22 行是仪器编号,最后一行是净收益。

样例
样例输入
2 3
10 1 2
25 2 3
5 6 7
样例输出
1 2
1 2 3
17
数据范围与提示

1≤n,m≤50 1 \leq n, m \leq 501n,m50


最大权闭合子图模板题

http://blog.csdn.net/qq_34564984/article/details/53471131

#include <iostream>
#include <cstdio>
#include <cstring>
#include <climits>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
const int N = 2100;
const int inf = 99999999;
int dis[N], lter[N];
struct node
{
    int to, cap, rev;
};
vector<node>p[N];
void add(int u,int v,int w)
{
    node tmp;
    tmp.to=v, tmp.cap=w,tmp.rev=p[v].size();
    p[u].push_back(tmp);
    tmp.to=u, tmp.cap=0,tmp.rev=p[u].size()-1;
    p[v].push_back(tmp);
    return ;
}

int bfs(int s,int t)
{
    memset(dis,-1,sizeof(dis));
    queue<int>q;
    dis[s]=0;
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=0; i<p[u].size(); i++)
        {
            int v=p[u][i].to;
            if(dis[v]==-1&&p[u][i].cap>0)
            {
                dis[v]=dis[u]+1;
                q.push(v);
            }
        }
    }
    return dis[t]==-1;
}

int dfs(int s,int t,int flow)
{
    if(s==t) return flow;
    for(int &i=lter[s]; i<p[s].size(); i++)
    {
        int v=p[s][i].to;
        if(dis[v]==dis[s]+1&&p[s][i].cap>0)
        {
            int f=dfs(v,t,min(flow,p[s][i].cap));
            if(f>0)
            {
                p[s][i].cap-=f, p[v][p[s][i].rev].cap+=f;
                return f;
            }
        }
    }
    return 0;
}

int dinic(int s,int e)
{
    int flow=0, f;
    while(1)
    {
        while(bfs(s,e)) return flow;
        memset(lter,0,sizeof(lter));
        while(f=dfs(s,e,inf),f>0)
        {
            flow+=f;
        }
    }
    return flow;
}
char str[N];
int a[N];
int main()
{
    int n, m, x,sum=0;
    scanf("%d %d", &n, &m);
    int s=0, e=n+m+1;
    for(int i=0;i<=e;i++)p[i].clear();
    for(int i=1;i<=n;i++)
    {
        scanf("%d ",&x);
        sum+=x;
        add(s,i,x);
        gets(str);
        for(int j=0;str[j]!='\n'&&str[j]!='\0';)
        {
            int w=0;
            while(str[j]>='0'&&str[j]<='9')
            {
                w=w*10+(str[j]-'0');
                j++;
            }
            if(w!=0) add(i,n+w,inf);
            else if(str[j]=='\n'||str[j]=='\0')break;
            else j++;
        }
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d", &x);
        add(n+i,e,x);
    }
    int ans=dinic(s,e);
    int k=0;
    for(int i=1;i<=n;i++) if(dis[i]!=-1) a[k++]=i;
    for(int i=0;i<k;i++) printf("%d%c",a[i],i==k-1?'\n':' ');
    k=0;
    for(int i=n+1;i<=n+m;i++) if(dis[i]!=-1) a[k++]=i-n;
    for(int i=0;i<k;i++) printf("%d%c",a[i],i==k-1?'\n':' ');
    printf("%d\n",sum-ans);
}









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值