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

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

代码如下:

 #include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cassert>
#include <cctype>
#include <queue> using namespace std;
const int MAXN = ;
const int INF = 0x3f3f3f3f; int n, sch[MAXN], home[MAXN]; template< int MAXN, int MAXSZ >
struct List {
int head[MAXN], nxt[MAXSZ], val[MAXSZ], lidx;
List() { clear(); }
void clear() {
lidx = ;
memset( head, -, sizeof(head) );
}
void ins( int n, int v ) {
val[lidx] = v; nxt[lidx] = head[n]; head[n] = lidx++;
}
}; template< int MAXV, int MAXE >
struct Dinic {
struct Edge {
int from, to, cap, flow;
Edge(){}
Edge( int from, int to, int cap, int flow ):
from(from),to(to),cap(cap),flow(flow){}
}edge[MAXE<<]; int eidx;
int s, t;
List<MAXV,MAXE<<> lst;
Dinic() { init(); }
void init() {
lst.clear(); eidx = ;
}
void adde( int from, int to, int cap ) {
edge[eidx] = Edge(from,to,cap,);
lst.ins(from,eidx++);
edge[eidx] = Edge(to,from,,);
lst.ins(to,eidx++);
}
queue<int> bfsq; bool vis[MAXV];
int dist[MAXV];
bool bfs() {
memset( vis, false, sizeof(vis) );
bfsq.push(s); vis[s] = true; dist[s] = ;
while( !bfsq.empty() ) {
int u = bfsq.front(); bfsq.pop();
for( int i = lst.head[u]; ~i; i = lst.nxt[i] ) {
Edge &e = edge[lst.val[i]]; int v = e.to;
if( !vis[v] && e.cap > e.flow ) {
vis[v] = true; dist[v] = dist[u] + ;
bfsq.push(v);
}
}
} return vis[t];
}
int cur[MAXV];
int dfs( int u, int res ) {
if( u == t || res == ) return res;
int flow = ;
if( cur[u] == INF ) cur[u] = lst.head[u];
for( int &i = cur[u]; ~i; i = lst.nxt[i] ) {
Edge &e = edge[lst.val[i]]; int v = e.to;
if( e.cap > e.flow && dist[v] == dist[u] + ) {
int nxtf = dfs( v, min( res, e.cap-e.flow ) );
if( nxtf == ) continue;
flow += nxtf; res -= nxtf;
e.flow += nxtf; edge[lst.val[i]^].flow -= nxtf;
if( res == ) break;
}
} return flow;
}
int solve( int s, int t ) {
int flow = ;
this->s = s; this->t = t;
while( bfs() ) {
memset( cur, 0x3f, sizeof(cur) );
flow += dfs(s,INF);
} return flow;
}
};
Dinic< MAXN<<, MAXN*(MAXN+) > dinic; // j表示点的类别
// 0表示人,1表示床,2表示s和t
inline int id( int i, int j ) {
return i+j*n;
} int main() {
int T; scanf( "%d", &T );
while( T-- ) {
scanf( "%d", &n ); dinic.init();
int need = n; // 需要住宿的人数
int s = id(,), t = id(,);
for( int i = ; i <= n; ++i ) {
scanf( "%d", sch+i );
if( sch[i] ) dinic.adde( id(i,), t, ); // 每个在校生都有床
}
for( int i = ; i <= n; ++i ) {
scanf( "%d", home+i );
if( !sch[i] ) home[i] = -; // 非在校生不存在回不回家
if( home[i] == ) need--; // 不需要住宿
else dinic.adde( s, id(i,), ); // 需要住宿
}
for( int i = ; i <= n; ++i ) for( int j = ; j <= n; ++j ) {
int rela; scanf( "%d", &rela );
if( home[i] == ) continue; // 回家的人不需要住宿
if( sch[i] && i == j ) dinic.adde( id(i,), id(j,), ); // 在校生可以睡自己的床
else if( sch[j] && rela ) dinic.adde( id(i,), id(j,), ); // 可以睡别人的床
}
int flow = dinic.solve(s,t);
if( flow == need ) printf( "^_^\n" );
else printf( "T_T\n" );
}
return ;
}

最新文章

  1. 【转】libevent和基于libevent的网络编程
  2. 一个页面中显示多个button时总行数计算公式。
  3. 关于code reiview
  4. 纸上谈兵:伸展树(splay tree)
  5. HTML 笔记,持续更新
  6. android Scroller类的理解
  7. NGINX(一)内存结构
  8. [Leveldb源码剖析疑问]-block_builder.cc之Add函数
  9. 带A圈的秘密
  10. mysqlbackup 备份失败的分析
  11. 使用gson(一)
  12. Java线程:线程安全类和Callable与Future(有返回值的线程)
  13. 201521123076《Java程序设计》第1周学习总结
  14. windows查看端口占用 windows端口占用 查找端口占用程序 强制结束端口占用 查看某个端口被占用的解决方法 如何查看Windows下端口占用情况
  15. C语言中gets(), scanf()区别
  16. git add -A -u . 的区别
  17. 3月22 关于CSS
  18. 修改SQL Server数据库表的创建时间最简单最直接有效的方法
  19. 软件测试——等价类划分(EditText * 3)
  20. AT指令框架的实现

热门文章

  1. leetcode个人题解——#22 Generate Parentheses
  2. HDU 2487 Ugly Windows(暴力)(2008 Asia Regional Beijing)
  3. es6从零学习(一)let 和 const 命令
  4. 《剑指Offer》题三十一~题四十
  5. Lecture Sleep(尺取+前缀和)
  6. 软工实践Alpha冲刺(2/10)
  7. Java容器之Iterator接口
  8. Dom的样式操作和属性操作
  9. nargout 【转】
  10. 【bzoj4417】[Shoi2013]超级跳马 矩阵乘法