zoukankan      html  css  js  c++  java
  • [2018多省省队联测]劈配

    题目

    第一问非常裸,就是一个动态加边的(dinic),我们从(1)(n)考虑每一个人的每一个志愿,每次把这个人这一志愿的所有边都连出来,跑最大流发现流量增加就说明这个志愿匹配上了,退出做下一个人;否则就做这个人的下一个志愿

    (dinic)的时候删掉没有用的边会让代码快很多

    第二问看起来非常二分,但是二分需要我们每次都重构出残量网络或者是暴力存下所有残量网络,这有点过于暴力了

    于是我们考虑每当我们构造出前(i)个人的残量网络的时候,我们就把之后的(n-i)个人的前(s)志愿的边加进来,跑(dinic)看看能否匹配,如果能匹配上我们给这个人记录一下,同时退流

    由于我们需要删掉这个人的所有边,我们没有必要完整退流,只需要把汇点向这个人所连的导师指向汇点的边给退流就好了

    代码

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #include<queue>
    #define re register
    #define LL long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    const int maxn=405;
    const int inf=1e9;
    inline int read() {
    	char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    std::vector<int> v[205][205];
    std::queue<int> q;
    struct E{int v,nxt,f;}e[maxn*maxn];
    int h[maxn*maxn];
    int Te,Cc,S,T,b[205],ans[205],a[205],vis[205],g[205],id[205];
    int n,m,tot,r[maxn],num;
    int head[maxn],d[maxn],cur[maxn];
    inline void C(int x,int y,int f) {
    	e[++num].v=y;e[num].nxt=head[x];
    	head[x]=num;e[num].f=f;h[num]=x;
    }
    inline void add(int x,int y,int f) {C(x,y,f),C(y,x,0);}
    inline int BFS() {
    	for(re int i=1;i<=tot;i++) d[r[i]]=0,cur[r[i]]=head[r[i]];
    	d[S]=1,q.push(S);
    	while(!q.empty()) {
    		int k=q.front();q.pop();
    		for(re int i=head[k];i;i=e[i].nxt)
    		if(!d[e[i].v]&&e[i].f) d[e[i].v]=d[k]+1,q.push(e[i].v);
    	}
    	return d[T];
    }
    int dfs(int x,int now) {
    	if(x==T||!now) return now;
    	int flow=0,ff;
    	for(re int& i=cur[x];i;i=e[i].nxt)
    	if(d[e[i].v]==d[x]+1) {
    		ff=dfs(e[i].v,min(e[i].f,now));
    		if(ff<=0) continue;
    		now-=ff,flow+=ff,e[i].f-=ff,e[i^1].f+=ff;
    		if(!now) break;
    	}
    	return flow;
    }
    inline void reBuild() {
    	tot=0;
    	S=0,T=n+m+1;
    	r[++tot]=S,r[++tot]=T;
    	for(re int i=1;i<=m;i++) 
    		r[++tot]=n+i,id[i]=num+1,add(n+i,T,b[i]);
    }
    inline void back(int pre) {
    	while(num>pre) {head[h[num]]=e[num].nxt;num--;} 
    }
    int main() {
    	Te=read(),Cc=read();
    	while(Te--) {
    		n=read(),m=read();
    		memset(head,0,sizeof(head));num=1;
    		memset(vis,0,sizeof(vis));
    		memset(ans,0,sizeof(ans));
    		for(re int i=1;i<=n;i++)
    			for(re int j=1;j<=m;j++)
    				v[i][j].clear();
    		for(re int i=1;i<=m;i++) b[i]=read();
    		for(re int i=1;i<=n;i++)
    			for(re int j=1;j<=m;j++) {
    				int k=read();
    				if(!k) continue;
    				v[i][k].push_back(j);
    			}
    		reBuild();
    		int now=0;
    		for(re int i=1;i<=n;i++) {
    			r[++tot]=i;add(S,i,1);now=num;
    			for(re int j=1;j<=m;j++) {
    				for(re int k=0;k<v[i][j].size();++k)
    					add(i,v[i][j][k]+n,1);
    				int mid=0;
    				while(BFS()) mid+=dfs(S,inf);
    				if(mid>=1) {ans[i]=j;break;}
    				back(now);
    			}
    		}
    		for(re int i=1;i<=n;i++) if(!ans[i]) ans[i]=m+1;
    		for(re int i=1;i<=n;i++) a[i]=read();
    		for(re int i=1;i<=n;i++) printf("%d ",ans[i]);
    		putchar(10);
    		memset(head,0,sizeof(head));num=1;
    		for(re int i=1;i<=n;i++) {
    			if(ans[i]<=a[i]) {vis[i]=1;g[i]=i;continue;}
    			for(re int j=1;j<=a[i];j++) vis[i]+=v[i][j].size();
    			if(vis[i]) vis[i]=0;
    				else vis[i]=1,g[i]=0;
    		}
    		for(re int i=1;i<=n;i++) if(!vis[i]) g[i]=1;
    		reBuild();
    		for(re int i=1;i<=n;i++) {
    			r[++tot]=i;add(S,i,1);now=num;
    			for(re int j=1;j<=m;j++) {
    				for(re int k=0;k<v[i][j].size();++k)
    					add(i,v[i][j][k]+n,1);
    				int mid=0;
    				while(BFS()) mid+=dfs(S,inf);
    				if(mid>=1) break;
    				back(now);
    			}
    			now=num;
    			for(re int j=i+2;j<=n;j++) {
    				if(vis[j]) continue;
    				r[++tot]=j;add(S,j,1);
    				for(re int p=1;p<=a[j];p++) 
    					for(re int k=0;k<v[j][p].size();k++)
    						add(j,v[j][p][k]+n,1);
    				int mid=0;
    				while(BFS()) mid+=dfs(S,inf);
    				if(mid>=1) {
    					g[j]=i+1;
    					for(re int k=head[j];k;k=e[k].nxt)
    					if(!e[k].f&&e[k].v>n) {
    						e[id[e[k].v-n]].f++;
    						e[id[e[k].v-n]^1].f--;
    						break;
    					}
    				}
    				tot--;back(now);
    			}
    		}
    		for(re int i=1;i<=n;i++) printf("%d ",i-g[i]);
    		putchar(10);
    	}
    	return 0;
    }
    
  • 相关阅读:
    解决ListView异步加载数据之后不能点击的问题
    android点击实现图片放大缩小 java技术博客
    关于 数据文件自增长 的一点理解
    RAC 实例不能启动 ORA1589 signalled during ALTER DATABASE OPEN
    Linux 超级用户的权利
    RAC 实例 迁移到 单实例 使用导出导入
    Shell 基本语法
    Linux 开机引导与关机过程
    RAC 实例不能启动 ORA1589 signalled during ALTER DATABASE OPEN
    Oracle RAC + Data Guard 环境搭建
  • 原文地址:https://www.cnblogs.com/asuldb/p/10611040.html
Copyright © 2011-2022 走看看