题面
题意
去太空飞行时,可以花费一些钱带一些实验器材,带够一些实验器材可以做一个实验获得一定利润,问最大净利润.
做法
与 洛谷 P3410 拍照相同,都是用最小割解最大权闭合图,但这题还要输出方案.
这道题不能根据边的剩余流量输出方案,因为剩余流量可能不为满流,也不为0,仅仅在满流为1时可以用这种方法输出流量.
正确做法是先求出最小割,然后依次去掉与每个器材有关的所有边,求一遍答案,若答案与不去边时的答案不同,则说明该边必要,这个器材要带,以此类推,可以求出所有要带仪器.
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<stack>
#include<vector>
#define C ch=getchar()
#define INF 0x3f3f3f3f
#define N 1010
#define M 1000100
using namespace std;
int bb,n,m,first[N],sum,s,t,cur[N],deep[N],ans,an,cst[N],val[N],tmp;
bool have[N],bh[N][N];
char ch;
struct Bn
{
int to,next,quan;
} bn[M];
queue<int>que;
vector<int>need[N];
inline void add(int u,int v,int w)
{
bb++;
bn[bb].to=v;
bn[bb].next=first[u];
bn[bb].quan=w;
first[u]=bb;
}
inline void ad(int u,int v,int w)
{
add(u,v,w);
add(v,u,0);
}
inline bool bfs()
{
int p,q;
for(; !que.empty(); que.pop());
memset(deep,0,sizeof(deep));
que.push(s);
deep[s]=1;
for(; !que.empty()&&!deep[t];)
{
q=que.front();
que.pop();
for(p=first[q]; p!=-1; p=bn[p].next)
{
if(deep[bn[p].to]||!bn[p].quan) continue;
deep[bn[p].to]=deep[q]+1;
que.push(bn[p].to);
}
}
return deep[t];
}
int dfs(int now,int mn)
{
if(now==t) return mn;
int res;
for(int &p=cur[now]; p!=-1; p=bn[p].next)
{
if(!bn[p].quan||deep[bn[p].to]!=deep[now]+1) continue;
res=dfs(bn[p].to,min(mn,bn[p].quan));
if(res)
{
bn[p].quan-=res;
bn[p^1].quan+=res;
return res;
}
}
return 0;
}
inline void init(int u)
{
int i,j;
memset(first,-1,sizeof(first));
bb=1,tmp=0;
for(i=1;i<=m;i++)
{
if(bh[i][u])
{
tmp+=val[i];
continue;
}
ad(s,i,val[i]);
for(j=0;j<need[i].size();j++)
{
ad(i,need[i][j]+m,INF);
}
}
for(i=1;i<=n;i++) if(i!=u) ad(i+m,t,cst[i]);
}
inline int mf()
{
int i,p,res=0;
for(; bfs();)
{
memcpy(cur,first,sizeof(cur));
for(p=dfs(s,INF); p; res+=p,p=dfs(s,INF));
}
return res;
}
int main()
{
int i,j,p,q;
cin>>m>>n;
t=m+n+1;
for(i=1; i<=m; i++)
{
scanf("%d",&val[i]);
sum+=val[i];
for(C;;)
{
for(; (ch<'0'||ch>'9')&&ch!='\n';C);
if(ch=='\n' || ch=='\r') break;
for(q=ch-48,C; ch>='0'&&ch<='9'; q=q*10+ch-48,C);
need[i].push_back(q),bh[i][q]=1;
}
}
for(i=1; i<=n; i++) scanf("%d",&cst[i]);
init(0);
ans=sum-mf();
for(i=1;i<=n;i++)
{
init(i);
if(sum-tmp-mf()!=ans) have[i]=1;
}
for(i=1; i<=m; i++)
{
for(j=0;j<need[i].size(); j++)
{
if(!have[need[i][j]]) break;
}
if(j==need[i].size()) printf("%d ",i);
}
puts("");
for(i=1; i<=n; i++) if(have[i]) printf("%d ",i);
puts("");
cout<<ans;
}