开发计划
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 ",tot-dinic(s,t));//盈利项目之和-最小割(最小割=最大流) pushin(0);//dfs求S集 sort(ans,ans+top); for(int i=1;i<top;i++)printf("%d ",ans[i]); return 0; }
读入十分恶心,交了37次才A过QAQ