LOJ6001太空飞行计划(网络流24题)

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

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

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

输出格式
第 1 1 1 行是实验编号,第 2 2 2 行是仪器编号,最后一行是净收益。

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


建模是很好想的
集合1里面的选了集合二对应的必须选
最大权闭合子图
或者跳过这一步我们也可以直接想到最小割的做法
考虑一个实验
S向实验连收益的边,实验向设备连INF的边,设备向T连话费的边
割前面表示不进行该实验,割后面表示进行实验
那答案就=所有收益减去最小割
转化为最大权闭合子图也是一样的道理

这题的两个坑点:
①读入鬼畜,换行符是’\r’,但是你写成’\n’居然也有分
②输出方案
这里输出方案我一开始图方便直接判断S连向实验的边权是否为0,设备连向T的边权是否为0
实际上这样是错的
为什么?
我们割前面的边不一定表示流量就为0,实际上可能我们割后面的边也会使前面的流量为0
后面也是同理

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int ans; 
int n , m , S , T;
int linkk[1100] , t , dep[1100];
bool flag;
const int oo = 0x7fffffff;
struct node{
    int n , y , v;
}e[1001000];
int read()
{
    int sum = 0;char c = getchar();bool flag = true;
    while( c < '0' || c > '9' ) {if(c == '-') flag = false;c = getchar();}
    while( c >= '0' && c <= '9' ) sum = sum * 10 + c - 48 , c = getchar();
    if(flag)  return sum;
     else return -sum;
}  
void insert(int x,int y,int z)
{
    e[++t].y = y;e[t].n = linkk[x];e[t].v = z;linkk[x] = t;
    e[++t].y = x;e[t].n = linkk[y];e[t].v = 0;linkk[y] = t;
}
void init()
{
    t = 1;
    n = read();m = read();S = n + m + 1;T = n + m + 2;
    for(int i = 1;i <= n;++i)
    {
        int x = read();
        ans += x;
        insert(S , i + m, x);
        while(1)
        {
            char c;
            scanf("%d%c",&x,&c);
            has[i][++has[i][0]] = x;
            insert(i + m, x , oo);
            if(c == '\r'|| c == '\n') break;
        }
    }
    for(int i = 1;i <= m;++i)
    {
        int x = read();
        insert(i , T , x);
    }
    return;
}
ll dfs(int x,ll lazy)
{
    if(x == T) return lazy;
    ll nowlazy = 0;
    ll d = 0;
    for(int i = linkk[x];i&&nowlazy < lazy;i = e[i].n)
    {
        int y = e[i].y;
        if(dep[y] == dep[x] + 1 && e[i].v > 0)
            if(d = dfs(y,min(1ll*e[i].v , lazy - nowlazy)))
            {
                nowlazy += d;
                e[i].v -= d;
                e[i^1].v += d; 
            }
    }
    if(nowlazy == 0) dep[x] = -1;
    return nowlazy;
}
queue<int>q;
bool bfs()
{
    memset(dep,-1,sizeof(dep));
    dep[S] = 0;q.push(S);
    while(q.size())
    {
        int v = q.front();
        for(int i = linkk[v];i;i = e[i].n)
            if(dep[e[i].y] == -1 && e[i].v > 0) 
                dep[e[i].y] = dep[v] + 1,q.push(e[i].y);
        q.pop();
    }
    if(dep[T] == -1) return false;
    return true;
}
int main()
{
    init();
    while(bfs())
    {       
        ll d;
        while(d = dfs(S,oo)) ans -=  d;
    }

    for(int i = 1;i <= n;++i)
        if(dep[i + m] >= 0)
            printf("%d ",i);
    printf("\n");
    for(int i = 1;i <= m;++i)
        if(dep[i] >= 0)
            printf("%d ",i);
    printf("\n%lld\n",ans);
    return 0;
} 

猜你喜欢

转载自blog.csdn.net/a1035719430/article/details/81276383