zoukankan      html  css  js  c++  java
  • 【题解】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( "^_^
    " );
    123         else printf( "T_T
    " );
    124     }
    125     return 0;
    126 }
  • 相关阅读:
    如何删除完全重复的列
    串联多个字符串,引发string和stringBuilder的比较
    借鉴ANJOU的方法改写了上次的TreeView
    如何改变ListBox中内容的顺序
    执行Insert语句时使用string的Format用法
    moss 2007 中FCKEditor编辑器的使用
    qt 获得cmd 命令运行的结果 GIS
    迭代器 GIS
    win32 创建带图片的button GIS
    c++标准库的构成 GIS
  • 原文地址:https://www.cnblogs.com/mlystdcall/p/6349348.html
Copyright © 2011-2022 走看看