【網絡流24題】太空飛行計劃問題

Luogu P2762

題意

給出m個實驗,給出每個實驗需要哪些儀器的編號和完成該實驗的收益。給出每個儀器的花費。每個儀器都可以在多次使用。求最大收益。並輸出具體方案(完成了哪些實驗,用了哪些儀器)

題解

不能貪心地解決,可能A實驗配置儀器後是虧的,但是配置完儀器後其他的實驗要配的儀器變少了,總的收益是更大的。

那麼解決這一類A事件的發生和B事件是否發生存在依賴關係,且每個事件都有一定收益(正收益或負收益)的問題,可以用網絡流中一個叫做最大權閉合圖的模型來解決。推薦一篇論文算法合集之《最小割模型在信息學競賽中的應用》,胡伯濤大佬寫的,其中有對該模型的詳細講解,寫的非常好。這篇論文也加深了我對網絡流問題的理解。

那麼這類問題怎麼解決,具體的證明過程看論文,這裏只給出建圖方法。

原來事件之間的依賴關係對應建一條流量爲inf的邊,超級源點向每個正收益的事件連一條流量爲該事件收益的邊,每個虧損的事件向超級匯點連一條流量爲虧損的邊。跑出的最大流即最小割是總體的最小虧損,拿所有正收益的事件求和,再減去這個最小虧損即是最大收益。

那麼還有一個問題,怎麼求出方案。這裏簡單講一下方法和大致原理。跑完最大流後搜一下殘量網絡,能與起點聯通的事件都選上。原理大致是最小割割掉的那些事件全部捨棄,剩下的就都是需要的事件。

對應到這道題目,做實驗是一個正收益的事件,但它依賴於配置儀器這些負收益的事件,那麼這樣就可以套用上述模型解決了。

代碼

直接粘的上古代碼......

#include<bits/stdc++.h>
#define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX 233
using namespace std;

int n,m,ANS=0,T;
int Du[MAX];
vector <int> f[MAX],flow[MAX],FB[MAX];
int dis[MAX];
int dl[2333];

bool BFS()
{
    int t=0,w=1,x,X;
    memset(dis,0xff,sizeof(dis));
    dl[1]=0;dis[0]=0;
    do
    {
        x=dl[++t];
        for(int i=0;i<Du[x];i++)
        {
            X=f[x][i];
            if(dis[X]>=0||!flow[x][i]) continue;
            dis[X]=dis[x]+1;
            dl[++w]=X;
        }
    }while(t!=w);
    if(dis[T]>0) return true;
    return false;
}
int DFS(int x,int MFLOW)
{
    if(x==T) return MFLOW;
    int X,h;
    for(int i=0;i<Du[x];i++)
    {
        X=f[x][i];
        if(dis[X]==dis[x]+1&&flow[x][i]>0&&(h=DFS(X,MIN(flow[x][i],MFLOW))))
        {
            flow[x][i]-=h;
            flow[X][FB[x][i]]+=h;
            return h;
        }
    }
    return 0;
}

void readin();
void work();
void print();

int main()
{
    readin();
    work();
    print();
    return 0;
}

void readin()
{
    int x;
    char c;
    scanf("%d%d",&n,&m);
    T=n+m+1;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&x);getchar();ANS+=x;
        Du[0]++;Du[i]++;
        f[0].push_back(i);flow[0].push_back(x);FB[0].push_back(Du[i]-1);
        f[i].push_back(0);flow[i].push_back(0);FB[i].push_back(Du[0]-1);
        while(1)
        {
            scanf("%d",&x);x+=n;
            c=getchar();
            Du[i]++;Du[x]++;
            f[i].push_back(x);flow[i].push_back(0x7fffffff);FB[i].push_back(Du[x]-1);
            f[x].push_back(i);flow[x].push_back(0);FB[x].push_back(Du[i]-1);
            if(c==13||c==10) break;
        }
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&x);
        Du[i+n]++;Du[T]++;
        f[i+n].push_back(T);flow[i+n].push_back(x);FB[i+n].push_back(Du[T]-1);
        f[T].push_back(i+n);flow[T].push_back(0);FB[T].push_back(Du[i+n]-1);
    }
}
void work()
{
    int x;
    while(BFS())
        while(x=DFS(0,0x7fffffff))
            ANS-=x;
    BFS();
}
void print()
{
    for(int i=1;i<=n;i++)
        if(dis[i]>=0)
            printf("%d ",i);
    putchar('\n');
    for(int i=1;i<=m;i++)
        if(dis[i+n]>=0)
            printf("%d ",i);
    putchar('\n');
    printf("%d",ANS);
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章