• [ZJOI2009]假期的宿舍


    洛咕

    题意:学校放假了 · · · · · · 有些同学回家了,而有些同学则有以前的好朋友来探访,那么住宿就是一个问题.比如 A 和 B 都是学校的学生,A 要回家,而 C 来看B,C 与 A 不认识.我们假设每个人只能睡和自己直接认识的人的床.那么一个解决方案就是 B 睡 A 的床而 C 睡 B 的床.而实际情况可能非常复杂,有的人可能认识好多在校学生,在校学生之间也不一定都互相认识.我们已知一共有 n 个人,并且知道其中每个人是不是本校学生,也知道每个本校学生是否回家.问是否存在一个方案使得所有不回家的本校学生和来看他们的其他人都有地方住.

    分析:网络流难就难在建图了.本题中可以看成一个二分图,左部分(A)是要睡床的人(如果是在校学生且回家,就不在该集合A中,否则都在),右部分(B)是床(数量为在校学生的人数,非本校学生本来是没有床位的).如果(i,j)认识就连边(i->j)的床,容量为1.当然,自己也要连自己的床.

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<set>
    #define ll long long
    using namespace std;
    inline int read(){
        int x=0,o=1;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')o=-1,ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*o;
    }
    const int N=100005;
    int n,s,t,max_flow,sum,sum1;
    int a[N],b[N],A[N],B[N],c[105][105];
    int visit[N],incf[N],pre[N];
    int tot,head[N],nxt[N],to[N],w[N];
    inline void add(int a,int b,int c){
    	nxt[++tot]=head[a];head[a]=tot;to[tot]=b;w[tot]=c;
    	nxt[++tot]=head[b];head[b]=tot;to[tot]=a;w[tot]=0;
    }
    inline bool bfs(){
    	memset(visit,0,sizeof(visit));
    	queue<int>q;q.push(s);visit[s]=1;incf[s]=1e9;
    	while(q.size()){
    		int u=q.front();q.pop();
    		for(int i=head[u];i;i=nxt[i]){
    			if(!w[i])continue;
    			int v=to[i];if(visit[v])continue;
    			incf[v]=min(incf[u],w[i]);
    			pre[v]=i;q.push(v);visit[v]=1;
    			if(v==t)return 1;
    		}
    	}
    	return 0;
    }
    inline void update(){
    	int x=t;
    	while(x!=s){
    		int i=pre[x];
    		w[i]-=incf[t];
    		w[i^1]+=incf[t];
    		x=to[i^1];
    	}
    	max_flow+=incf[t];
    }
    int main(){
    	int T=read();
    	while(T--){
    		n=read();tot=1;max_flow=0;sum=0;sum1=0;//初始化
    		memset(head,0,sizeof(head));
    		for(int i=1;i<=n;++i){
    			a[i]=read();
    			if(!a[i])A[++sum]=i;//非本校学生是一定要睡床的,加入左部分
    		}
    		for(int i=1;i<=n;++i){
    			b[i]=read();
    			if(a[i]&&!b[i])A[++sum]=i;//本校学生且不回家也是要睡床的
    		}
    		for(int i=1;i<=n;++i)if(a[i])B[++sum1]=i;//只有在校学生才有床位	
    		for(int i=1;i<=n;++i)
    			for(int j=1;j<=n;++j)
    				c[i][j]=read();
    		for(int i=1;i<=sum;++i)
    			for(int j=1;j<=sum1;++j)
    				if(c[A[i]][B[j]]||A[i]==B[j])add(i+1,j+sum+1,1);//建二分图
    		s=1;t=sum+sum1+2;
    		for(int i=1;i<=sum;++i)add(s,i+1,1);		
    		for(int j=1;j<=sum1;++j)add(j+sum+1,t,1);//二分图变网络流
    		while(bfs())update();
    		if(max_flow==sum)printf("^_^
    ");
    		else printf("T_T
    ");
    	}
        return 0;
    }
    
    
  • 相关阅读:
    自相关函数 互相关函数 平稳随机过程
    MC323发短信程序+MSP430F149
    labview notes
    DSSS FHSS
    dBm与功率(w)换算关系!
    int 正负相乘
    51单片机 1602液晶显示
    51单片机 AD转换
    51单片机 蜂鸣器
    51单片机 串口通信
  • 原文地址:https://www.cnblogs.com/PPXppx/p/11614802.html
Copyright © 2020-2023  润新知