试题库问题[网络流]

传送门

源点向每个试题连边 , 每个试题向类型连边 , 类型向汇点连边 , 流量为个数

这样如果最大流是需要的总和,就是有解的 , 将方向边不为0的点输出就可以了


#include<bits/stdc++.h>
#define N 5050
#define M 100050
#define inf 0x3fffffff
using namespace std;
int first[N],next[M],to[M],w[M],tot=1;
int n,k,st,ed,dis[N],vis[N],ans,cnt; 
vector<int> V[N];
void add(int x,int y,int z){
	next[++tot]=first[x],first[x]=tot,to[tot]=y,w[tot]=z;
	next[++tot]=first[y],first[y]=tot,to[tot]=x,w[tot]=0;
}
bool bfs(){
	memset(dis,127,sizeof(dis));
	memset(vis,0,sizeof(vis));
	dis[st]=0 , vis[st]=1; int Inf = dis[1];
	queue<int> q; q.push(st);
	while(!q.empty()){
		int x=q.front(); q.pop();
		for(int i=first[x];i;i=next[i]){
			int t=to[i]; if(!vis[t] && w[i]){
				vis[t]=1; dis[t]=dis[x]+1;
				q.push(t);
			}
		}
	}return dis[ed] != Inf;
}
int dfs(int u,int flow){
	if(u==ed) return flow;
	int ans=0;
	for(int i=first[u];i;i=next[i]){
		int t=to[i];
		if(dis[t]==dis[u]+1 && w[i]){
			int delta=dfs(t,min(w[i],flow));
			flow -= delta; ans += delta;
			w[i] -= delta; w[i^1] += delta;
			if(flow==0) break;
		} 
	}return ans;
}
void dinic(){
	while(bfs()) ans+=dfs(st,inf);
}
int main(){
	cin>>k>>n; st=0,ed=n+k+1;
	for(int i=1;i<=k;i++){
		int x; scanf("%d",&x); add(i+n,ed,x); cnt += x;
	}
	for(int i=1;i<=n;i++){
		add(st,i,1);
		int x; scanf("%d",&x);
		for(int j=1;j<=x;j++){
			int y; scanf("%d",&y); add(i,y+n,1);
		}
	}
	dinic(); if(ans != cnt){printf("No Solution!"); return 0;}
	for(int i=n+1;i<=n+k;i++){
		for(int j=first[i];j;j=next[j]){
			if(j&1 && w[j]) V[i-n].push_back(to[j]);
		}
	}
	for(int i=1;i<=k;i++){
		printf("%d: ",i);
		int siz=V[i].size();
		for(int j=0;j<siz;j++) printf("%d ",V[i][j]); 
		printf("\n");
	} return 0;
}

猜你喜欢

转载自blog.csdn.net/sslz_fsy/article/details/84899278