• [网络流24题]试题库问题


    题目:洛谷P2763。

    题目大意:一个试题库有n道试题,现在要选m道题组成试卷。共有k种类型的题目,每种类型各需要若干题。每一种题目有一些不同的类型,但选择这道题只能选定它一个类型。现在要你设计一种试卷的组成方案。如果不能满足条件输出No Solution!

    解题思路:网络流。

    首先建立超级源点S和超级汇点T。

    对于每个试题,从S向该试题连一条容量为1的边(因为每道试题只能用一次)。

    对于每个试题对应的类型,从该试题分别向这些类型连一条容量为1的边。

    对于每个类型,从该类型向T连一条边,容量为该类型所需要的题目数量。

    然后做一遍最大流即可。

    如果最大流不等于m,则说明无解,输出No Solution!

    否则输出方案即可。

    输出方案,我用了如下办法:

    首先枚举题目类型,然后枚举与它有关的边。如果这条边连接的不是T(那么只可能是连向题目的反向边)且有剩余容量(说明正向的该条边被流过),则输出之。

    然后让SPJ自己判断吧。

    C++ Code:

    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<queue>
    #define M 5005
    #define inf 0x3fffffff
    std::queue<int>q;
    int k,n,head[M],cnt=-1,level[M],iter[M];
    struct edge{
    	int to,cap,nxt;
    }e[M*M];
    inline int readint(){
    	char c=getchar();
    	for(;!isdigit(c);c=getchar());
    	int d=0;
    	for(;isdigit(c);c=getchar())d=(d<<3)+(d<<1)+(c^'0');
    	return d;
    }
    inline void addedge(int u,int v,int flow){
    	++cnt;
    	e[cnt]=(edge){v,flow,head[u]};
    	head[u]=cnt;
    	++cnt;
    	e[cnt]=(edge){u,0,head[v]};
    	head[v]=cnt;
    }
    void bfs(int s,int t){
    	level[s]=1;
    	q.push(s);
    	while(!q.empty()){
    		int u=q.front();
    		q.pop();
    		for(int i=head[u];i!=-1;i=e[i].nxt)
    		if(level[e[i].to]==-1&&e[i].cap){
    			level[e[i].to]=level[u]+1;
    			q.push(e[i].to);
    		}
    	}
    }
    int dfs(int u,int t,int f){
    	if(u==t)return f;
    	for(int& i=iter[u];i!=-1;i=e[i].nxt)
    	if(level[e[i].to]>level[u]&&e[i].cap){
    		int d=dfs(e[i].to,t,f>e[i].cap?e[i].cap:f);
    		if(d){
    			e[i].cap-=d;
    			e[i^1].cap+=d;
    			return d;
    		}
    	}
    	return 0;
    }
    int maxflow(int s,int t){
    	for(int flow=0;;){
    		memset(level,-1,sizeof level);
    		bfs(s,t);
    		if(level[t]==-1)return flow;
    		memcpy(iter,head,sizeof iter);
    		int f;
    		while(f=dfs(s,t,inf))flow+=f;
    	}
    }
    int main(){
    	k=readint(),n=readint();
    	memset(head,-1,sizeof head);
    	int all=0;
    	for(int i=1;i<=k;++i){
    		int p=readint();
    		all+=p;
    		addedge(i+n,k+n+1,p);
    	}
    	for(int i=1;i<=n;++i){
    		addedge(0,i,1);
    		for(int p=readint();p--;){
    			int x=readint();
    			addedge(i,x+n,1);
    		}
    	}
    	int mf;
    	if((mf=maxflow(0,n+k+1))!=all)return!printf("No Solution!
    ");
    	for(int i=n+1;i<=k+n;++i){
    		printf("%d:",i-n);
    		for(int j=head[i];j!=-1;j=e[j].nxt)
    		if(e[j].to<=n&&e[j].cap)printf(" %d",e[j].to);
    		putchar('
    ');
    	}
    	return 0;
    }
  • 相关阅读:
    Maven版本管理
    ArrayList集合实现RandomAccess接口有何作用?为何LinkedList集合却没实现这接口
    java常用集合框架关系
    重写equals和hashCode
    项目的继承和聚合详解
    Installation Manager1.8安装
    关于java按位操作运算
    正数负数的二进制表示
    springboot问题排解
    int和Integer有什么区别
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/8244501.html
Copyright © 2020-2023  润新知