【题解】ZJOI2009 假期的宿舍 网络流 最大流

好久没有来写博客啦,来水一发。

网络流建模
首先很容易想到,如果一个人能睡一张床,那么在这个人和这张床之间连接一条容量为1的边
从s向每个需要住宿的人连容量为1的边,表示这个人需要住宿
从每张床向t连容量为1的边,表示这个床容纳了一个人
求最大流,如果流量等于需要住宿的人数,则有解,否则无解
分析一下,一共需要2*n+2个点,n*n+2*n条有向边

代码如下:

  1 #include <iostream>
  2 #include <cstring>
  3 #include <algorithm>
  4 #include <cstdio>
  5 #include <cmath>
  6 #include <cstdlib>
  7 #include <cassert>
  8 #include <cctype>
  9 #include <queue>
 10 
 11 using namespace std;
 12 const int MAXN = 55;
 13 const int INF = 0x3f3f3f3f;
 14 
 15 int n, sch[MAXN], home[MAXN];
 16 
 17 template< int MAXN, int MAXSZ >
 18 struct List {
 19     int head[MAXN], nxt[MAXSZ], val[MAXSZ], lidx;
 20     List() { clear(); }
 21     void clear() {
 22         lidx = 0;
 23         memset( head, -1, sizeof(head) );
 24     }
 25     void ins( int n, int v ) {
 26         val[lidx] = v; nxt[lidx] = head[n]; head[n] = lidx++;
 27     }
 28 };
 29 
 30 template< int MAXV, int MAXE >
 31 struct Dinic {
 32     struct Edge {
 33         int from, to, cap, flow;
 34         Edge(){}
 35         Edge( int from, int to, int cap, int flow ):
 36             from(from),to(to),cap(cap),flow(flow){}
 37     }edge[MAXE<<1]; int eidx;
 38     int s, t;
 39     List<MAXV,MAXE<<1> lst;
 40     Dinic() { init(); }
 41     void init() {
 42         lst.clear(); eidx = 0;
 43     }
 44     void adde( int from, int to, int cap ) {
 45         edge[eidx] = Edge(from,to,cap,0);
 46         lst.ins(from,eidx++);
 47         edge[eidx] = Edge(to,from,0,0);
 48         lst.ins(to,eidx++);
 49     }
 50     queue<int> bfsq; bool vis[MAXV];
 51     int dist[MAXV];
 52     bool bfs() {
 53         memset( vis, false, sizeof(vis) );
 54         bfsq.push(s); vis[s] = true; dist[s] = 0;
 55         while( !bfsq.empty() ) {
 56             int u = bfsq.front(); bfsq.pop();
 57             for( int i = lst.head[u]; ~i; i = lst.nxt[i] ) {
 58                 Edge &e = edge[lst.val[i]]; int v = e.to;
 59                 if( !vis[v] && e.cap > e.flow ) {
 60                     vis[v] = true; dist[v] = dist[u] + 1;
 61                     bfsq.push(v);
 62                 }
 63             }
 64         } return vis[t];
 65     }
 66     int cur[MAXV];
 67     int dfs( int u, int res ) {
 68         if( u == t || res == 0 ) return res;
 69         int flow = 0;
 70         if( cur[u] == INF ) cur[u] = lst.head[u];
 71         for( int &i = cur[u]; ~i; i = lst.nxt[i] ) {
 72             Edge &e = edge[lst.val[i]]; int v = e.to;
 73             if( e.cap > e.flow && dist[v] == dist[u] + 1 ) {
 74                 int nxtf = dfs( v, min( res, e.cap-e.flow ) );
 75                 if( nxtf == 0 ) continue;
 76                 flow += nxtf; res -= nxtf;
 77                 e.flow += nxtf; edge[lst.val[i]^1].flow -= nxtf;
 78                 if( res == 0 ) break;
 79             }
 80         } return flow;
 81     }
 82     int solve( int s, int t ) {
 83         int flow = 0;
 84         this->s = s; this->t = t;
 85         while( bfs() ) {
 86             memset( cur, 0x3f, sizeof(cur) );
 87             flow += dfs(s,INF);
 88         } return flow;
 89     }
 90 };
 91 Dinic< MAXN<<1, MAXN*(MAXN+2) > dinic;
 92 
 93 // j表示点的类别
 94 // 0表示人,1表示床,2表示s和t
 95 inline int id( int i, int j ) {
 96     return i+j*n;
 97 }
 98 
 99 int main() {
100     int T; scanf( "%d", &T );
101     while( T-- ) {
102         scanf( "%d", &n ); dinic.init();
103         int need = n; // 需要住宿的人数
104         int s = id(1,2), t = id(2,2);
105         for( int i = 1; i <= n; ++i ) {
106             scanf( "%d", sch+i );
107             if( sch[i] ) dinic.adde( id(i,1), t, 1 ); // 每个在校生都有床
108         }
109         for( int i = 1; i <= n; ++i ) {
110             scanf( "%d", home+i );
111             if( !sch[i] ) home[i] = -1; // 非在校生不存在回不回家
112             if( home[i] == 1 ) need--; // 不需要住宿
113             else dinic.adde( s, id(i,0), 1 ); // 需要住宿
114         }
115         for( int i = 1; i <= n; ++i ) for( int j = 1; j <= n; ++j ) {
116             int rela; scanf( "%d", &rela );
117             if( home[i] == 1 ) continue; // 回家的人不需要住宿
118             if( sch[i] && i == j ) dinic.adde( id(i,0), id(j,1), 1 ); // 在校生可以睡自己的床
119             else if( sch[j] && rela ) dinic.adde( id(i,0), id(j,1), 1 ); // 可以睡别人的床
120         }
121         int flow = dinic.solve(s,t);
122         if( flow == need ) printf( "^_^\n" );
123         else printf( "T_T\n" );
124     }
125     return 0;
126 }

 

posted @ 2017-01-25 13:16  mlystdcall  阅读(327)  评论(0编辑  收藏  举报