版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/83244522
洛谷传送门
LOJ传送门
(LOJ输出有毒,testlib对行末空格很敏感,所以我这份代码的输出不是很清真。。。)
解析:
感觉好像就是这道题的弱化版。。。
所以不如先把上面这道题A了再来做这道?
不过这里就只需要仪器向汇点连边,项目向源点连边,仪器和对应项目之间连容量为 的边就行了。
关于输出方案:
其实本来想记录一下每条需要的边的位置,根据最终容量计算的,后来发现不需要。
我们只需要找出最后一次 预处理仍然在层次图里面的就行了。 似乎做法是一样的。
为什么可以这样呢?
首先,如果我们找出了合法的项目,那么由于它与仪器之间连了 的边,所以所有的需要的机器都会被构建在层次图里面,反之,如果一个机器不被需要,那么说明它没有为任何一个合法的项目带来帮助,应当被舍弃。
那么为什么所有合法的项目都在最终的层次图里面呢?
我在刚才链接那道题的题解里面已经解释了每条边容量的意义,这里不再赘述,直入主题。
显然最终需要选择的项目与源点之间还有残量存在。
。。。好的那么它必然会被构造进层次图里面,反之,它就没有被构造进层次图的必要了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
cs int N=102,M=3000,INF=0x3f3f3f3f;
cs int S=0,T=N-1;
int last[N],nxt[M<<1],to[M<<1],ecnt=1;
int cap[M<<1];
inline int addedge(int u,int v,int val){
nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v,cap[ecnt]=val;
nxt[++ecnt]=last[v],last[v]=ecnt,to[ecnt]=u,cap[ecnt]=0;
return ecnt-1;
}
int lev[N];
int cur[N];
inline bool BFS(){
queue<int> q;
memset(lev,-1,sizeof lev);
lev[S]=0;
q.push(S);
cur[S]=last[S];
while(!q.empty()){
int u=q.front();
q.pop();
for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
if(cap[e]&&lev[v]==-1){
lev[v]=lev[u]+1;
if(v==T)return true;
cur[v]=last[v];
q.push(v);
}
}
}
return false;
}
int Dinic(cs int &u,cs int &flow){
if(u==T)return flow;
int ans=0;
for(int &e=cur[u],v=to[e];e;v=to[e=nxt[e]]){
if(cap[e]&&lev[v]>lev[u]){
int delta=Dinic(v,min(flow-ans,cap[e]));
if(delta){
cap[e]-=delta;
cap[e^1]+=delta;
ans+=delta;
if(ans==flow)return flow;
}
}
}
return ans;
}
inline int maxflow(){
int ans=0;
while(BFS())ans+=Dinic(S,INF);
return ans;
}
int n,m,tot;
char ss[100000];
signed main(){
scanf("%d%d",&n,&m);
for(int re i=1;i<=n;++i){
int val;
scanf("%d",&val);
tot+=val;
addedge(S,i,val);
cin.getline(ss,100000);
int now=0;
while(sscanf(ss+now,"%d",&val)==1){
addedge(i,val+50,INF);
do{
++now;
val/=10;
}while(val);
++now;
}
}
for(int re i=1;i<=m;++i){
int val;scanf("%d",&val);
addedge(i+50,T,val);
}
int ans=tot-maxflow();
bool flag=false;
for(int re i=1;i<=n;++i){
if(~lev[i]){
if(!flag)flag=true;
else pc(' ');
printf("%d",i);
}
}
pc('\n');
flag=false;
for(int re i=1;i<=m;++i){
if(~lev[i+50]){
if(!flag)flag=true;
else pc(' ');
printf("%d",i);
}
}
pc('\n');
cout<<ans;
return 0;
}