zoukankan      html  css  js  c++  java
  • [八省联考 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;
    }
    
  • 相关阅读:
    【Language】 TIOBE Programming Community Index for February 2013
    【diary】good health, good code
    【web】a little bug of cnblog
    【Git】git bush 常用命令
    【web】Baidu zone ,let the world know you
    【diary】help others ,help yourself ,coding is happiness
    【Git】Chinese messy code in widows git log
    【windows】add some font into computer
    SqlServer启动参数配置
    关于sqlserver中xml数据的操作
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/14380879.html
Copyright © 2011-2022 走看看