开发计划

开发计划

baidu,google我都试过了,全网都没有这题的题解,只有一份pascal的标程,于是决定造福人类

Description

Juicepry®公司准备制定一份未来一段时期内的科研与产品开发计划。公司的各部门,都提出各自的计划项目,汇总成一张计划表。该计划表包含了许多项目,每个项目是一个研究课题,一个技术试验,一项市场调查,或者是一个推销活动,等等。对于每个项目,计划表中都给出了它的预算,开支或者盈利。由于某些项目的进行必须依赖其他项目的成果,所以如果要进行这个项目的话,它所依赖的项目也是必不可少的。例如,要推出一个新产品,先要分析其消费群体的需求,对产品的性能做出定位,然后设计产品的各个细节,包括形象包装,等等。现在假设你是Juicipry®公司的总裁,你的目标是从这份计划项目表中挑选出一些项目,使得你的公司能获得最大的利润。

Input

包括项目的数量N,以及每个项目的预算Ci和他所依赖的项目集合Pi。格式如下:
第1行是N;
第2~n+1行每行表示一个项目的信息。
每行第一个数是Ci,正数表示盈利,负数表示开支。剩下的数表示项目i所依赖的项目。每行相邻的两个数之间用一个或多个空格隔开。
0≤N≤3000
-1000000≤Ci≤1000000

Output

第1行是公司的最大利润。接着是获得最大利润的方案。若有多个方案,则输出所选项目最少的。每行一个数,表示选择的项目,所有项目按从小到大排序。

Solution

网络流建图:

对于每个项目,将其视为一个点,源点为s=0,汇点为t=n+1

若p项目盈利(ci>0),则将s与p连边,容量为ci

若p项目亏损(ci<0),则将p与t连边,容量为-ci

若p项目依赖q,则将p与q连边,容量为inf

建完图跑一遍dinic就好了\(^o^)/

则 纯获利=盈利项目之和-最小割

那么选择的项目就是S集中的点啦,dfs求出来就好了

Code

#include<bits/stdc++.h>
#define inf 0x7fffffff
#define N 3005
using namespace std;
int n,st,ed,tot,s,t,lw[N],head[N],cnt=1,dis[N];
struct Line{int to,nxt,val;}l[N*N];
void ins(int x,int y,int z){
    l[++cnt].to=y,l[cnt].nxt=head[x],l[cnt].val=z,head[x]=cnt;
    l[++cnt].to=x,l[cnt].nxt=head[y],l[cnt].val=0,head[y]=cnt;
}
bool bfs(){
    memset(dis,0,sizeof(dis));
    queue<int>q;
    dis[st]=1,q.push(st);
    while(q.size()){
        int x=q.front();q.pop();
        for(int i=head[x],y;i;i=l[i].nxt){
            y=l[i].to;
            if(l[i].val&&!dis[y]){
                dis[y]=dis[x]+1;
                if(y==ed)return true;
                q.push(y);
            }
        }
    }
    return false;
}
int dfs(int x,int limit){
    if(x==ed)return limit;
    int tmp=limit;
    for(int i=head[x],k,y;i;i=l[i].nxt){
        y=l[i].to;
        if(dis[y]!=dis[x]+1||!l[i].val)continue;
        if((k=dfs(y,min(tmp,l[i].val)))){
            l[i^1].val+=k,l[i].val-=k;
            tmp-=k;
        }else dis[y]=0;
        if(!tmp)return limit;
    }
    return limit-tmp;
}
int dinic(int S,int T){
    st=S,ed=T;int re=0;
    while(bfs())re+=dfs(st,inf);
    return re;
}
int ans[N],top;
bool vis[N];
void pushin(int x){
    if(!vis[x])vis[x]=true,ans[top++]=x;
    else return;
    for(int i=head[x];i;i=l[i].nxt){
        if(!l[i].val)continue;
        pushin(l[i].to);
    }
}
signed main(){
    scanf("%d",&n),s=0,t=n+1;
    for(int i=1,ci,ai;i<=n;i++){
        scanf("%d",&ci);
        if(ci>0)tot+=ci,ins(s,i,ci);
        if(ci<0)ins(i,t,-ci);
        char ch;
        while(~scanf("%c",&ch)){
            if(ch!=' ')break;
            scanf("%d",&ai);
            ins(i,ai,inf);
        }
    }
    printf("%d\n",tot-dinic(s,t));//盈利项目之和-最小割(最小割=最大流)
    pushin(0);//dfs求S集
    sort(ans,ans+top);
    for(int i=1;i<top;i++)printf("%d\n",ans[i]);
    return 0;
}

读入十分恶心,交了37次才A过QAQ

posted @ 2019-01-25 10:56  The_KOG  阅读(381)  评论(0编辑  收藏  举报