• [八省联考 2018] 劈配


    题目

    传送门

    解法

    第一次做动态加边的网络流。

    首先将导师向 (T) 连边权为 (b_i) 的边。

    对于第一问,每次 基于上一个选手的图,从小到大枚举每档志愿,从 (S)(i) 连边,从 (i) 向对应档的所有导师连边,边权均为 (1)。然后用 (mathtt{Dinic}) 判断能否找到一条增广路即可。

    对于第二问,容易发现增加名次越多,就越有可能不沮丧,这是可以二分的。判断就是从 (S)(i) 连边,从 (i)(1sim s_i) 档的所有导师连边。

    详见代码。

    代码

    #include <cstdio>
    
    #define rep(i,_l,_r) for(register signed i=(_l),_end=(_r);i<=_end;++i)
    #define fep(i,_l,_r) for(register signed i=(_l),_end=(_r);i>=_end;--i)
    #define erep(i,u) for(signed i=head[u],v=to[i];i;i=nxt[i],v=to[i])
    #define efep(i,u) for(signed i=Head[u],v=to[i];i;i=nxt[i],v=to[i])
    #define print(x,y) write(x),putchar(y)
    
    template <class T> inline T read(const T sample) {
        T x=0; int f=1; char s;
        while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
        while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
        return x*f;
    }
    template <class T> inline void write(const T x) {
        if(x<0) return (void) (putchar('-'),write(-x));
        if(x>9) write(x/10);
        putchar(x%10^48);
    }
    template <class T> inline T Max(const T x,const T y) {if(x>y) return x; return y;}
    template <class T> inline T Min(const T x,const T y) {if(x<y) return x; return y;}
    template <class T> inline T fab(const T x) {return x>0?x:-x;}
    template <class T> inline T gcd(const T x,const T y) {return y?gcd(y,x%y):x;}
    template <class T> inline T lcm(const T x,const T y) {return x/gcd(x,y)*y;}
    template <class T> inline T Swap(T &x,T &y) {x^=y^=x^=y;}
    
    #include <queue>
    #include <vector>
    #include <cstring>
    using namespace std;
    
    const int maxn=205,maxm=maxn*30,inf=1e9;
    
    vector <int> Xie[maxn][maxn];
    queue <int> q;
    int n,m,im[maxn];
    struct Graph {
    	int cnt,head[maxn<<1],nxt[maxm],to[maxm],flow[maxm];
    	int dep[maxn<<1],arc[maxn<<1];
    
    	void addEdge(int u,int v,int w) {
    		nxt[++cnt]=head[u],to[cnt]=v,flow[cnt]=w,head[u]=cnt;
    		nxt[++cnt]=head[v],to[cnt]=u,flow[cnt]=0,head[v]=cnt;
    	}
    
    	bool bfs() {
    		rep(i,0,401) dep[i]=inf;
    		while(!q.empty()) q.pop();
    		q.push(0),arc[0]=head[0],dep[0]=0;
    		while(!q.empty()) {
    			int u=q.front(); q.pop();
    			erep(i,u)
    				if(flow[i]>0 && dep[v]==inf) {
    					dep[v]=dep[u]+1;
    					arc[v]=head[v],q.push(v);
    					if(v==401) return 1;
    				}
    		}
    		return 0;
    	}
    
    	int dfs(int u,int CanFlow) {
    		if(u==401) return CanFlow;
    		int SumFlow=0,d;
    		for(int i=arc[u];i;i=nxt[i]) {
    			int v=to[i];
    			arc[u]=i;
    			if(flow[i]>0 && dep[v]==dep[u]+1) {
    				d=dfs(v,Min(CanFlow,flow[i]));
    				if(!d) dep[v]=inf;
    				SumFlow+=d,CanFlow-=d;
    				flow[i]-=d,flow[i^1]+=d;
    				if(!CanFlow) break;
    			}
    		}
    		return SumFlow;
    	}
    
    	bool Dinic() {
    		bool flag=0;
    		while(bfs()) dfs(0,inf),flag=1;
    		return flag;
    	}
    } s[maxn];
    
    bool OK(int pos,int i) {
    	s[201]=s[pos-1];
    	// 上升到了第 pos 名,前一个就是 pos-1
    	s[201].addEdge(0,i,1);
    	rep(j,1,im[i]) for(int k=0;k<Xie[i][j].size();++k) s[201].addEdge(i,Xie[i][j][k],1);
    	return s[201].Dinic();
    }
    
    int main() {
    	int x,T=read(9),C=read(9),l,r,mid,ans;
    	while(T--) {
    		n=read(9),m=read(9);
            memset(s,0,sizeof s);
    		s[0].cnt=1;
            rep(i,1,n) rep(j,1,m) Xie[i][j].clear();
    		rep(i,1,m) {
    			x=read(9);
    			s[0].addEdge(i+200,401,x);
    		}
    		rep(i,1,n) rep(j,1,m) {
    			x=read(9);
    			Xie[i][x].push_back(j+200);
    		}
    		rep(i,1,n) im[i]=read(9);
    		rep(i,1,n) rep(j,1,m) {
    			s[i]=s[i-1];
    			s[i].addEdge(0,i,1);
    			for(int p=0;p<Xie[i][j].size();++p) s[i].addEdge(i,Xie[i][j][p],1);
    			if(s[i].Dinic()) {print(j,' '); break;}
    			if(j==m) print(m+1,' ');
    		}
    		puts("");
    		rep(i,1,n) {
    			l=0,ans=i,r=i-1;
    			// 关于这里的二分:如果 r 赋值为 i,那么由于限定 l=r 时结束,那么 mid 就可能等于 i,就会出现 RE。当然可以做 [l,r) 的二分,这样答案就是 l/r
    			while(l<=r) {
    				mid=l+r>>1;
    				if(OK(i-mid,i)) ans=mid,r=mid-1;
    				else l=mid+1;
    			}
    			print(ans,' ');
    		}
    		puts("");
    	}
    	return 0;
    }
    
  • 相关阅读:
    过用户层HOOK思路
    Linux LVM实践
    matlab演奏卡农 Cripple Pachebel's Canon on Matlab
    rman备份恢复总结
    郁金香VC外挂教程(全) 翻录版 免Key(精品教程)
    C# string 中的 @ 作用处理\等字符
    (抓)2分法通用存储过程分页(top max模式)版本(性能相对之前的not in版本极大提高)
    怎样应用OracleParameter怎样写like查询语句?
    (转)DirectoryEntry的使用
    解决模式对话框和window.open打开新页面Session会丢失问题
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/14380879.html
Copyright © 2020-2023  润新知