调了一下午的网络流, 最后发现是因为想要用0作为下标而遍历的时候还是用习惯性的写法, 简直不开心。
网络流的题目基本都是重点在建模上, 我们来看看这一题怎么建模: 首先, 学生人数和可用床数是确定的, 我们就自己创造一个源点和一个汇点。 考虑到学生必须全部有床睡, 那么从原点出发流到床再流到学生即可。 这时我们能够机智的发现一件事, 其实就是求一个二分图的最大匹配, 愤愤然地感觉自己被坑了。 最终只要看匹配数是否等于有需求的学生数即可。
另一件事就是判断有需求的学生, 只要是外来的或校内但不回家的就是有需求的。
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cstdlib>
#define N 200
#define M 20000
#define INF 10000000
using namespace std;
struct edge
{
int to, next;
}e[M];
int t, n, num, ans, cont;
int a[N], b[N], p[N], mat[N], flag[N];
void add(int x, int y)
{
e[num].to = y;
e[num].next = p[x];
p[x] = num++;
}
void clean()
{
ans = num = cont = 0;
memset(p, -1, sizeof p);
memset(e, 0, sizeof e);
memset(mat, 0, sizeof mat);
}
void init()
{
clean();
int x;
scanf("%d", &n);
t = n << 1 | 1;
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
for (int i = 1; i <= n; ++i)
scanf("%d", &b[i]);
for (int i = 1; i <= n; ++i)
if (!a[i] || (a[i] && !b[i])) ++cont;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
{
scanf("%d", &x);
if (((i == j && a[i]) || (x && a[j])) && (!a[i] || (a[i] && !b[i])))
{
add(j+n, i);
add(i, j+n);
}
}
}
bool find(int x)
{
for (int i = p[x]; i != -1; i = e[i].next)
{
int k = e[i].to;
if (!flag[k])
{
flag[k] = 1;
if (!mat[k] || find(mat[k]))
{
mat[k] = x;
return true;
}
}
}
return false;
}
void deal()
{
for (int i = 1; i <= n; ++i)
{
memset(flag, 0, sizeof flag);
ans += find(i);
}
if (ans == cont) printf("^_^\n");
else printf("T_T\n");
}
int main()
{
freopen("a.in", "r", stdin);
int T;
scanf("%d", &T);
while(T--)
{
init();
deal();
}
return 0;
}//二分图匹配代码
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cstdlib>
#define N 200
#define M 20000
#define INF 10000000
using namespace std;
struct edge
{
int to, next, cap, flow;
}e[M];
int t, n, num, ans, cont;
int a[N], b[N], p[N], d[N], flag[N], now[N];
void add(int x, int y, int z)
{
e[num].to = y;
e[num].next = p[x];
e[num].cap = z;
p[x] = num++;
}
void clean()
{
ans = num = cont = 0;
memset(p, -1, sizeof p);
memset(d, 0, sizeof d);
memset(e, 0, sizeof e);
}
void init()
{
clean();
int x;
scanf("%d", &n);
t = n << 1 | 1;
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
for (int i = 1; i <= n; ++i)
scanf("%d", &b[i]);
for (int i = 1; i <= n; ++i)
if (!a[i] || (a[i] && !b[i]))
{
add(i, t, 1);
add(t, i, 0);
++cont;
}
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
{
scanf("%d", &x);
if (((i == j && a[i]) || (x && a[j])) && (!a[i] || (a[i] && !b[i])))
{
add(j+n, i, 1);
add(i, j+n, 0);
}
}
for (int i = 1; i <= n; ++i)
if (a[i])
{
add(0, i+n, 1);
add(i+n, 0, 0);
}
}
bool bfs()
{
memset(flag, 0, sizeof flag);
d[0] = 0, flag[0] = 1;
queue<int>q;
q.push(0);
while(!q.empty())
{
int x = q.front();
q.pop();
for (int i = p[x]; i != -1; i = e[i].next)
{
int k = e[i].to;
if (!flag[k] && e[i].cap > e[i].flow)
{
flag[k] = 1;
d[k] = d[x] + 1;
q.push(k);
}
}
}
for (int i = 0; i <= t; ++i) now[i] = p[i];
return flag[t];
}
int dfs(int x, int mini)
{
if (x == t || !mini) return mini;
int flow = 0;
for (int i = now[x]; i != -1; i = e[i].next)
{
now[x] = i;
int k = e[i].to;
if (d[k] == d[x] + 1)
{
int tmp = dfs(k, min(mini, e[i].cap-e[i].flow));
if (tmp <= 0) continue;
e[i].flow += tmp;
e[i^1].flow -= tmp;
flow += tmp;
mini -= tmp;
if (!mini) break;
}
}
return flow;
}
void deal()
{
while(bfs()) ans += dfs(0, INF);
if (ans == cont) printf("^_^\n");
else printf("T_T\n");
}
int main()
{
freopen("a.in", "r", stdin);
freopen("a.out", "w", stdout);
int T;
scanf("%d", &T);
while(T--)
{
init();
deal();
}
return 0;
}//网络流代码