[ZJOI2009]假期的宿舍
OJ题号:
洛谷2055、BZOJ1433
思路:
将需要住宿的学生与超极源点$S$连一条边,将所有的床与超极汇点$T$连一条边。
将每个人与可以睡的床连一条边。
最大流跑二分图最大匹配即可。
连边时注意细节。
1 #include<queue> 2 #include<cstdio> 3 #include<cctype> 4 #include<vector> 5 #include<cstring> 6 inline int getint() { 7 char ch; 8 while(!isdigit(ch=getchar())); 9 int x=ch^'0'; 10 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 11 return x; 12 } 13 const int inf=0x7fffffff; 14 int s,t; 15 struct Edge { 16 int from,to; 17 bool remain; 18 }; 19 const int E=5200,V=202; 20 Edge e[E]; 21 std::vector<int> g[V]; 22 int sz; 23 inline void add_edge(const int u,const int v,const bool w) { 24 e[sz]=(Edge){u,v,w}; 25 g[u].push_back(sz); 26 sz++; 27 } 28 int p[V]; 29 bool a[V]; 30 inline bool Augment() { 31 memset(a,0,sizeof a); 32 a[s]=inf; 33 std::queue<int> q; 34 q.push(s); 35 while(!q.empty()&&!a[t]) { 36 int x=q.front(); 37 q.pop(); 38 for(unsigned i=0;i<g[x].size();i++) { 39 Edge &y=e[g[x][i]]; 40 if(!a[y.to]&&y.remain) { 41 p[y.to]=g[x][i]; 42 a[y.to]=a[x]&&y.remain; 43 q.push(y.to); 44 } 45 } 46 } 47 return a[t]; 48 } 49 inline int EdmondsKarp() { 50 int maxflow=0; 51 while(Augment()) { 52 for(int i=t;i!=s;i=e[p[i]].from) { 53 e[p[i]].remain^=true; 54 e[p[i]^1].remain^=true; 55 } 56 maxflow++; 57 } 58 return maxflow; 59 } 60 inline void reset() { 61 sz=0; 62 for(int i=0;i<V;i++) { 63 g[i].clear(); 64 } 65 } 66 int main() { 67 for(int T=getint();T;T--) { 68 reset(); 69 int n=getint(); 70 s=0,t=n<<1|1; 71 bool isStudent[n+1]; 72 for(int i=1;i<=n;i++) { 73 if(isStudent[i]=(bool)getint()) { 74 add_edge(n+i,t,true); 75 add_edge(t,n+i,false); 76 } 77 } 78 int cnt=0; 79 for(int i=1;i<=n;i++) { 80 if(!getint()||!isStudent[i]) { 81 add_edge(s,i,true); 82 add_edge(i,s,false); 83 cnt++; 84 } 85 } 86 for(int i=1;i<=n;i++) { 87 for(int j=1;j<=n;j++) { 88 if(getint()||(i==j)) { 89 add_edge(i,n+j,true); 90 add_edge(n+j,i,false); 91 } 92 } 93 } 94 puts(EdmondsKarp()==cnt?"^_^":"T_T"); 95 } 96 return 0; 97 }