洛谷 2763 试题库问题

裸题,只要找准建边的方法就好了,跑一遍最大流,枚举从试题编号指向类型相连的单向边,如果其flow(flt[ ])的值为0,那么说明这道题就选了是不是;


洛谷OJ是Special Judge,随便输出哪一个正确的就好了。


#include<bits/stdc++.h>



const int N=1000+4,M=1000000+10,K=30+5;


using namespace std;


queue<int> q;


int head[M],flt[M],nxt[M],to[M],cn=1;
int ans[K][N],dis[N],num[K];
int n,k,x,tmp,src,sink,inf=1e8+7;
bool vis[N];


int minx(int a,int b){
return a < b ? a : b ;
}


void create(int u,int v,int f){

cn++;
to[cn]=v;
flt[cn]=f;
nxt[cn]=head[u];
head[u]=cn;

cn++;
to[cn]=u;
flt[cn]=0;
nxt[cn]=head[v];
head[v]=cn;

}


bool bfs(){
int v;
memset(dis,0,sizeof(dis));
memset(vis,false,sizeof(vis));

q.push(src);
vis[src]=true;

while(!q.empty()){
tmp=q.front();
for(int i=head[tmp];i;i=nxt[i]){
v=to[i];
if(flt[i] && !vis[v]){
dis[v]=dis[tmp]+1;
q.push(v);
vis[v]=true;
}
}
q.pop();
}

return dis[sink]>0;
}


int dinic(int u,int delta){
if(u==sink) return delta;
int res=0,v;
for(int i=head[u];i && delta;i=nxt[i]){
v=to[i];
if(flt[i] && dis[v]==dis[u]+1){
int dd=dinic(v,minx(flt[i],delta));
flt[i]-=dd;
delta-=dd;
flt[i^1]+=dd;
res+=dd;
}
}
return res;
}


int main(){
ios::sync_with_stdio(false);

cin>>k>>n;
for(int i=1+n;i<=k+n;i++)
cin>>num[i];

src=0;sink=k+n+1;

for(int i=1;i<=n;i++)
create(src,i,1);

for(int i=1;i<=n;i++){
cin>>x;
for(int j=1;j<=x;j++){
cin>>tmp;
create(i,tmp+n,1);
}
}

for(int i=n+1;i<=n+k;i++)
create(i,sink,num[i]);

while(bfs())
   dinic(src,inf);

for(int i=1;i<=n;i++){
for(int j=head[i];j;j=nxt[j]){
   int v=to[j];
if(!flt[j])
       ans[v][++ans[v][0]]=i;
}
}

for(int i=1;i<=k;i++){
cout<<i<<": ";
for(int j=1;j<=ans[i+n][0];j++)
   cout<<ans[i+n][j]<<" ";
cout<<endl;
}

return 0;

}


加油!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值