P4382 [八省联考 2018] 劈配
作者:互联网
题面自己看吧、
std
对于第一问,容易想到是二分图匹配。
具体模型:
- \(s\) 向学生连流量为 \(1\) 的边。
- 导师向 \(t\) 连流量为人数限制的边。
- 从第一个学生的第一志愿往里面加边,如果当前学生的当前志愿可以满足,即目前网络流可以满流,保留这一志愿的边,然后下一个学生;否则,删除这一志愿的边,然后下一个志愿。
对于第二问,可以枚举这个学生要前进多少名。
假设当前学生 \(i\) 前进 \(x\) 名。
那么把学生 \(i\) 的可以使他不沮丧的所有志愿的所有边连上。
再把前 \(i - x - 1\) 名学生满足第一问中的志愿的边连上。
判断是否满流即可。
总结:动态加边网络流。
#include <bits/stdc++.h>
using namespace std;
namespace Fread
{
const int SIZE = 1 << 23;
char buf[SIZE], *S, *T;
inline char getchar()
{
if (S == T)
{
T = (S = buf) + fread(buf, 1, SIZE, stdin);
if (S == T)
return '\n';
}
return *S++;
}
}
namespace Fwrite
{
const int SIZE = 1 << 23;
char buf[SIZE], *S = buf, *T = buf + SIZE;
inline void flush()
{
fwrite(buf, 1, S - buf, stdout);
S = buf;
}
inline void putchar(char c)
{
*S++ = c;
if (S == T)
flush();
}
struct NTR
{
~NTR()
{
flush();
}
} ztr;
}
#ifdef ONLINE_JUDGE
#define getchar Fread::getchar
#define putchar Fwrite::putchar
#endif
inline int read()
{
int x = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9')
{
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9')
{
x = x * 10 + c - '0';
c = getchar();
}
return x * f;
}
inline void write(int x)
{
if(x < 0)
{
putchar('-');
x = -x;
}
if(x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
typedef int tp;
const int _ = 3e3 + 10;
int n, m, s, t, lv[_], cur[_];
int tot = 1, head[_], mcp[_], to[_ << 1], nxt[_ << 1];
tp w[_ << 1];
inline void add(int u, int v, tp dis)
{
to[++tot] = v;
nxt[tot] = head[u];
w[tot] = dis;
head[u] = tot;
}
inline void Add(int u, int v, tp dis)
{
add(u, v, dis);
add(v, u, 0);
}
inline bool bfs()
{
memset(lv, -1, sizeof(lv));
lv[s] = 0;
memcpy(cur, head, sizeof(head));
queue<int> q;
q.push(s);
while (!q.empty())
{
int p = q.front();
q.pop();
for (int eg = head[p]; eg; eg = nxt[eg])
{
int v = to[eg];
tp vol = w[eg];
if (vol > 0 && lv[v] == -1)
lv[v] = lv[p] + 1, q.push(v);
}
}
return lv[t] != -1;
}
tp dfs(int p = s, tp flow = 2e9)
{
if (p == t)
return flow;
tp rmn = flow;
for (int eg = cur[p]; eg && rmn; eg = nxt[eg])
{
cur[p] = eg;
int v = to[eg];
tp vol = w[eg];
if (vol > 0 && lv[v] == lv[p] + 1)
{
tp c = dfs(v, min(vol, rmn));
rmn -= c;
w[eg] -= c;
w[eg ^ 1] += c;
}
}
return flow - rmn;
}
inline tp dinic()
{
tp ans = 0;
while (bfs())
ans += dfs();
return ans;
}
int a[207][207], b[_], sv[_], A[_], tv[_], f[_];
inline void init()
{
tot = 1;
memset(head, 0, sizeof head);
s = 0, t = _ - 1;
for(int i = 1; i <= n; ++i)
Add(s, i, 1);
for(int i = 1; i <= m; ++i)
Add(i + n, t, b[i]);
memcpy(mcp, head, sizeof head);
}
signed main()
{
int T = read();
read();
while(T--)
{
n = read(), m = read();
for(int i = 1; i <= m; ++i)
b[i] = read();
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
a[i][j] = read();
for(int i = 1; i <= n; ++i)
sv[i] = read();
init();
int Fl = 0, bef = 0;
for(int i = 1; i <= n; ++i)
{
int id = m + 1, rnt = tot;
for(int j = 1; j <= m; ++j)
{
for(int k = 1; k <= m; ++k)
if(a[i][k] == j)
Add(i, k + n, 1);
Fl += dinic();
if(Fl ^ bef)
{
id = j, bef = Fl;
break;
}
else
{
tot = rnt;
memcpy(head, mcp, sizeof mcp);
}
}
A[i] = Fl, tv[i] = id;
memcpy(mcp, head, sizeof head);
}
for(int i = 1; i <= n; ++i)
write(tv[i]), putchar(' ');
putchar('\n');
for(int i = 1; i <= n; ++i)
{
init();
for(int j = 1; j <= m; ++j)
if(a[i][j] && a[i][j] <= sv[i])
Add(i, j + n, 1);
Fl = dinic();
if(!Fl)
{
f[i] = i;
continue;
}
for(int j = 1; j < i; ++j)
{
for(int k = 1; k <= m; ++k)
if (a[j][k] == tv[j]) Add(j, k + n, 1);
Fl += dinic();
if (Fl != A[j] + 1)
{
f[i] = i - j;
break;
}
}
}
for(int i = 1; i <= n; ++i)
write(f[i]), putchar(' ');
putchar('\n');
memset(f, 0, sizeof f);
}
return 0;
}
标签:八省,int,eg,tp,lv,志愿,P4382,rmn,联考 来源: https://www.cnblogs.com/orzz/p/16025373.html