【BZOJ 1433】[ZJOI2009]假期的宿舍
2018-05-25 16:24
344 查看
【链接】 我是链接,点我呀:)
【题意】
在这里输入题意
【题解】
把每个人都分为左边和右边两个人
xi,yi
如果第i个人不回家或者是外校学生
那么它可以和他认识的人连一条容量为1的边(前提是这个认识的人是本校的学生)
(从左边连向右边
然后源点向每个不回家的本校人或者外校人连一条容量为1的边。
(边的终点是左边的人
每个不是外校的人向汇点T连一条容量为1的边。
(边的起点是右边的人
做一下最大流就可以了
看看最大流和需要安排床位的人的人数相同不相同就可以了
(其实也就是二分图匹配,每条匹配就对应了给每个人分配一个床位的过程
(左边是需要分配床位的那些人,右边是有床的人。。
【代码】
#include <bits/stdc++.h> #define LL long long #define rep1(i,a,b) for (int i = a;i <= b;i++) #define rep2(i,a,b) for (int i = a;i >= b;i--) #define all(x) x.begin(),x.end() #define pb push_back #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 using namespace std; const double pi = acos(-1); const int dx[4] = {0,0,1,-1}; const int dy[4] = {1,-1,0,0}; const int N = 50; int n,r[N+10],l[N+10],cnt,a[N+10][N+10]; struct abc{ int en,nex; LL flow; }; int s,t,deep[N*2+20]; int fir[N*2+10],tfir[N*2+10],totm; abc bian[2*N*N+4*N+10]; queue <int> dl; void add(int x,int y,LL cost){ bian[totm].nex = fir[x]; fir[x] = totm; bian[totm].en = y,bian[totm].flow = cost; totm++; bian[totm].nex = fir[y]; fir[y] = totm; bian[totm].en = x,bian[totm].flow = 0; totm++; } bool bfs(int s,int t){ dl.push(s); memset(deep,255,sizeof deep); deep[s] = 0; while (!dl.empty()){ int x = dl.front(); dl.pop(); for (int temp = fir[x]; temp!= -1 ;temp = bian[temp].nex){ int y = bian[temp].en; if (deep[y]==-1 && bian[temp].flow>0){ deep[y] = deep[x] + 1; dl.push(y); } } } return deep[t]!=-1; } LL dfs(int x,int t,LL limit){ if (x == t) return limit; if (limit == 0) return 0; LL cur,f = 0; for (int temp = tfir[x];temp!=-1;temp = bian[temp].nex){ tfir[x] = temp; int y = bian[temp].en; if (deep[y] == deep[x] + 1 && (cur = dfs(y,t,min(limit,(LL)bian[temp].flow))) ){ f += cur; limit -= cur; bian[temp].flow -= cur; bian[temp^1].flow += cur; if (!limit) break; } } return f; } int main(){ #ifdef LOCAL_DEFINE freopen("rush_in.txt", "r", stdin); #endif ios::sync_with_stdio(0),cin.tie(0); int T; cin>>T; while (T--){ int students = 0; //如果不是在校学生 那么右边没有点 //因为他没有床位,不用考虑这个点的入度 totm = 0; memset(fir,255,sizeof fir); memset(r,0,sizeof r); memset(l,0,sizeof l); cnt = 0; cin >> n; for (int i = 1;i <= n;i++){ int x; cin >> x; if (x==1) r[i]=++cnt; } //如果回家的话,左边没有和他相关的点。 //不用考虑这个点的出度 for (int i = 1;i <= n;i++){ int x; cin >> x; if (r[i]==0) { l[i] = ++cnt; students++; continue; } if (x==0) { l[i] = ++cnt; students++; } } for (int i = 1;i <= n;i++) for (int j = 1;j <= n;j++) cin >> a[i][j]; for (int i = 1;i <= n;i++){ //是本校学生,但是回家 //不用给它安排 if (l[i]==0){ continue; } if (l[i]>0 && r[i]==0){ //不是本校学生 for (int j = 1;j <= n;j++) if (i!=j && a[i][j] && r[j]!=0){//那个人必须是本校学生 add(l[i],r[j],1); } } //是本校学生,且不走 if (l[i]>0 && r[i]>0){ for (int j = 1;j <= n;j++) if ( (a[i][j] && r[j]!=0) || (i==j)){ add(l[i],r[j],1); } } } for (int i = 1;i <= n;i++) if (l[i]!=0){//这个人不回家 add(0,l[i],1); } ++cnt; for (int i = 1;i <= n;i++) if (r[i]!=0){//不是外校的学生就有床位 add(r[i],cnt,1); } s = 0;t = cnt; int ans = 0; while (bfs(s,t)){ for (int i = 0;i <= cnt;i++) tfir[i] = fir[i]; ans += dfs(s,t,1000); } if (ans==students){ cout<<"^_^"<<endl; }else{ cout<<"T_T"<<endl; } } return 0; }
相关文章推荐
- [二分图最大匹配] BZOJ1433: [ZJOI2009]假期的宿舍
- bzoj1433: [ZJOI2009]假期的宿舍(二分图匹配)
- bzoj1433[ZJOI2009]假期的宿舍
- 【BZOJ 1433】 [ZJOI2009]假期的宿舍
- BZOJ 1433: [ZJOI2009]假期的宿舍
- bzoj1433[ZJOI2009]假期的宿舍
- BZOJ 1433: [ZJOI2009]假期的宿舍【二分图匹配】
- BZOJ 1433 [ZJOI2009]假期的宿舍(网络流)
- BZOJ1433: [ZJOI2009]假期的宿舍
- 【bzoj1433】 ZJOI2009—假期的宿舍
- bzoj1433 [ZJOI2009]假期的宿舍(最大流)
- bzoj 1433: [ZJOI2009]假期的宿舍
- BZOJ 1433: [ZJOI2009]假期的宿舍 二分图最大匹配
- [BZOJ1433][ZJOI2009]假期的宿舍(最大流)
- BZOJ 1433: [ZJOI2009]假期的宿舍 二分匹配
- BZOJ1433 [ZJOI2009]假期的宿舍
- 【bzoj1433】[ZJOI2009]假期的宿舍
- bzoj1433 [ZJOI2009]假期的宿舍
- bzoj1433 [ZJOI2009]假期的宿舍
- 【BZOJ 1433】 [ZJOI2009]假期的宿舍