这个专题是之前做的专题中做的最轻松的,毕竟只要想出建图就ok了。
建图有两个套路。如果是对一条边限制的话,那么就可以直接把容量变成那个限制就行了。而对点有限制的话,那么我们可以进行拆点,把点的限制转化成边限制。先来一道经典的建图题,只要把这题体会清楚了,那么之后的建图也就会清晰很多。
A - ACM Computer Factory
把工厂拆成2个点,两个点间的容量就为他最大的容量。之后根据他们的关系建图就行了(主要是拆点)。
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
const int maxv = 55;
const int inf = 0x3f3f3f3f;
struct Edge
{
int from, to, cap, flow;
Edge(int u, int v, int c, int f) :from(u), to(v), cap(c), flow(f) {}
Edge() {}
};
struct Dinic
{
int n, m, s, t;
vector<Edge>edges;
vector<int>G[maxv + 50];
bool vis[maxv + 50];
int d[maxv + 50];
int cur[maxv + 50];
void AddEdge(int from, int to, int cap)
{
edges.push_back(Edge(from, to, cap, 0));
edges.push_back(Edge(to, from, 0, 0));
m = edges.size();
G[from].push_back(m - 2);
G[to].push_back(m - 1);
}
void init(int n)
{
for (int i = 0;i <= n;i++)G[i].clear();
edges.clear();
}
bool BFS()
{
memset(vis, 0, sizeof(vis));
queue<int>Q;
Q.push(s);
d[s] = 0;
vis[s] = 1;
while (!Q.empty())
{
int x = Q.front();Q.pop();
for (int i = 0;i < G[x].size();i++)
{
Edge&e = edges[G[x][i]];
if (!vis[e.to] && e.cap > e.flow)
{
vis[e.to] = 1;
d[e.to] = d[x] + 1;
Q.push(e.to);
}
}
}
return vis[t];
}
int DFS(int x, int a)
{
if (x == t || a == 0)return a;
int flow = 0, f;
for (int &i = cur[x];i < G[x].size();i++)
{
Edge&e = edges[G[x][i]];
if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow)))>0)
{
e.flow += f;
edges[G[x][i] ^ 1].flow -= f;
flow += f;
a -= f;
if (a == 0)break;
}
}
return flow;
}
int Maxflow(int s, int t)
{
//cout << edges.size() << endl;
this->s = s;this->t = t;
int flow = 0;
while (BFS())
{
memset(cur, 0, sizeof(cur));
flow += DFS(s, inf);
}
return flow;
}
}ans;
int w[maxv];
int p[maxv][15];
int P, N;
bool check(int u, int num)
{
if (num == 0)
{
for (int i = 1;i <= P;i++)
if (p[u][i] == 1)return 0;
return 1;
}
if (num == 1)
{
for (int i = P+1;i <= 2*P;i++)if (p[u][i] == 0)return 0;
return 1;
}
}
bool check1(int a, int b)
{
for (int i = 1;i <= P;i++)
{
int tmpa = p[a][i + P];
int tmpb = p[b][i];
if (tmpa + tmpb == 1)return 0;
}
return 1;
}
bool vis[3000];
int main()
{
scanf("%d %d", &P, &N);
for (int i = 1;i <= N;i++)
{
scanf("%d", &w[i]);
for (int j = 1;j <= 2*P;j++)
scanf("%d", &p[i][j]);
}
int s = 0, t = 2 * N + 1;
int n = 2 * N + 1;
ans.init(n);
for (int i = 1;i <= N;i++)
ans.AddEdge(i, i + N, w[i]);
for (int i = 1;i <= N;i++)
{
if (check(i, 0))
ans.AddEdge(s, i, inf);
if (check(i, 1))
ans.AddEdge(i + N, t, inf);
for (int j = 1;j <= N;j++)if (check1(i, j))
ans.AddEdge(i + N, j, inf);
}
printf("%d ", ans.Maxflow(s, t));
int routenum = 0;
for (int i = 0;i < ans.edges.size();i += 2)
{
Edge &e = ans.edges[i];
if (e.flow > 0&&e.from!=s&&e.to!=t&&e.from+N!=e.to)
vis[i]=1, routenum++;
}
printf("%d\n", routenum);
for (int i = 0;i < ans.edges.size();i += 2)if (vis[i])
{
Edge &e = ans.edges[i];
//cout << i << " ";
printf("%d %d %d\n", e.from-N, e.to, e.flow);
}
}
G - Island Transport
这题主要卡dinic,在这里贴一下ispa模板。
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
using namespace std;
int head[210000], s, t, nv, maxint=0x3f3f3f3f, cnt;
int cur[210000], pre[210000], q[5000000], d[210000], num[210000];
struct node
{
int u, v, cap, next;
}edge[11000000];
void add(int u, int v, int cap)
{
edge[cnt].v=v;
edge[cnt].cap=cap;
edge[cnt].next=head[u];
head[u]=cnt++;
edge[cnt].v=u;
edge[cnt].cap=cap;
edge[cnt].next=head[v];
head[v]=cnt++;
}
void bfs()
{
memset(num,0,sizeof(num));
memset(d,-1,sizeof(d));
int f1=0, f2=0, i;
q[f1++]=t;
d[t]=0;
num[0]=1;
while(f1>=f2)
{
int u=q[f2++];
for(i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(d[v]==-1)
{
d[v]=d[u]+1;
num[d[v]]++;
q[f1++]=v;
}
}
}
}
void isap()
{
memcpy(cur,head,sizeof(cur));
int flow=0, u=pre[s]=s, i;
bfs();
while(d[s]<nv)
{
if(u==t)
{
int f=maxint, pos;
for(i=s;i!=t;i=edge[cur[i]].v)
{
if(f>edge[cur[i]].cap)
{
f=edge[cur[i]].cap;
pos=i;
}
}
for(i=s;i!=t;i=edge[cur[i]].v)
{
edge[cur[i]].cap-=f;
edge[cur[i]^1].cap+=f;
}
flow+=f;
//printf("--");
u=pos;
}
for(i=cur[u];i!=-1;i=edge[i].next)
{
if(d[edge[i].v]+1==d[u]&&edge[i].cap)
{
break;
}
}
if(i!=-1)
{
cur[u]=i;
pre[edge[i].v]=u;
u=edge[i].v;
}
else
{
if(--num[d[u]]==0) break;
int mind=nv+1;
for(i=head[u];i!=-1;i=edge[i].next)
{
if(mind>d[edge[i].v]&&edge[i].cap)
{
mind=d[edge[i].v];
cur[u]=i;
}
}
d[u]=mind+1;
num[d[u]]++;
u=pre[u];
}
}
printf("%d\n",flow);
}
int read(){
int flag = 0, x = 0;
char ch = ' ';
while(ch != '-' && (ch > '9' || ch < '0')) ch = getchar();
if(ch == '-') flag = 1, ch = getchar();
while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
return flag ? -x : x;
}
int main()
{
int T, n, m, i, j, a, b, c, x, y, min1, max1;
scanf("%d",&T);
while(T--)
{
memset(head,-1,sizeof(head));
cnt=0;
n=read();m=read();
min1=999999;
max1=-999999;
for(i=1;i<=n;i++)
{
x=read();y=read();
if(min1>x)
{
min1=x;
s=i;
}
if(max1<x)
{
max1=x;
t=i;
}
}
while(m--)
{
a=read();
b=read();
c=read();
add(a,b,c);
}
nv=n+1;
isap();
}
return 0;
}
I - Control
这题又卡ispa。。。所以用dinic。。(并不知道什么时候用哪个好)
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include<vector>
#include<queue>
using namespace std;
const int maxv = 500;
const int inf = 0x3f3f3f3f;
struct Edge
{
int from, to, cap, flow;
Edge(int u, int v, int c, int f) :from(u), to(v), cap(c), flow(f) {}
Edge() {}
};
struct Dinic
{
int n, m, s, t;
vector<Edge>edges;
vector<int>G[maxv + 50];
bool vis[maxv + 50];
int d[maxv + 50];
int cur[maxv + 50];
void AddEdge(int from, int to, int cap)
{
edges.push_back(Edge(from, to, cap, 0));
edges.push_back(Edge(to, from, 0, 0));
m = edges.size();
G[from].push_back(m - 2);
G[to].push_back(m - 1);
}
void init(int n)
{
for (int i = 0;i <= n;i++)G[i].clear();
edges.clear();
}
bool BFS()
{
memset(vis, 0, sizeof(vis));
queue<int>Q;
Q.push(s);
d[s] = 0;
vis[s] = 1;
while (!Q.empty())
{
int x = Q.front();Q.pop();
for (int i = 0;i < G[x].size();i++)
{
Edge&e = edges[G[x][i]];
if (!vis[e.to] && e.cap > e.flow)
{
vis[e.to] = 1;
d[e.to] = d[x] + 1;
Q.push(e.to);
}
}
}
return vis[t];
}
int DFS(int x, int a)
{
if (x == t || a == 0)return a;
int flow = 0, f;
for (int &i = cur[x];i < G[x].size();i++)
{
Edge&e = edges[G[x][i]];
if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow)))>0)
{
e.flow += f;
edges[G[x][i] ^ 1].flow -= f;
flow += f;
a -= f;
if (a == 0)break;
}
}
return flow;
}
int Maxflow(int s, int t)
{
//cout << edges.size() << endl;
this->s = s;this->t = t;
int flow = 0;
while (BFS())
{
memset(cur, 0, sizeof(cur));
flow += DFS(s, inf);
}
return flow;
}
}ans;
int s, t;
int main()
{
int N, M;
while (~scanf("%d %d",&N,&M))
{
ans.init(2 * N + 5);
int w;
scanf("%d %d", &s, &t);
t += N;
for (int i = 1;i <= N;i++)
scanf("%d", &w), ans.AddEdge(i, i + N, w);
int u, v;
for (int i = 1;i <= M;i++)
{
scanf("%d %d", &u, &v);
ans.AddEdge(u + N, v, inf);
ans.AddEdge(v + N, u, inf);
}
printf("%d\n", ans.Maxflow(s,t));
}
return 0;
}
J - Sabotage
最小割模板题,这里复习一下最小割最大流定理:当用cost=最大流把图中的一些边拆掉时,会把图分成两部分。
这里用EdmondsKarp模板,这里面刚好有一个a来记录结点在哪部分。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include<iostream>
using namespace std;
const int maxn = 55;
const int inf = 0x3f3f3f3f;
struct Edge
{
int from, to, cap, flow;
Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){}
};
struct EdmondsKarp
{
int n, m;
vector<Edge>edges;
vector<int>G[maxn];
int a[maxn];
int p[maxn];
void init(int n)
{
for (int i = 0;i <= n;i++)G[i].clear();
edges.clear();
}
void AddEdge(int from, int to, int cap)
{
edges.push_back(Edge(from, to, cap, 0));
edges.push_back(Edge(to, from, cap, 0));
m = edges.size();
G[from].push_back(m - 2);
G[to].push_back(m - 1);
}
int Maxflow(int s, int t)
{
int flow = 0;
for (;;)
{
memset(a, 0, sizeof(a));
queue<int>Q;
Q.push(s);
a[s] = inf;
while (!Q.empty())
{
int x = Q.front();Q.pop();
for (int i = 0;i < G[x].size();i++)
{
Edge &e = edges[G[x][i]];
if (!a[e.to] && e.cap > e.flow)
{
p[e.to] = G[x][i];
a[e.to] = min(a[x], e.cap - e.flow);
Q.push(e.to);
}
}
if (a[t])break;
}
if (!a[t])break;
for (int u = t;u != s;u = edges[p[u]].from)
{
edges[p[u]].flow += a[t];
edges[p[u] ^ 1].flow -= a[t];
}
flow += a[t];
}
return flow;
}
}ans;
int U[505], V[505];
int main()
{
int n, m;
int s = 1, t = 2;
while (~scanf("%d %d", &n, &m) && n)
{
ans.init(n);
int u, v, d;
for (int i = 1;i <= m;i++)
{
scanf("%d %d %d", &u, &v, &d);
U[i] = u, V[i] = v;
ans.AddEdge(u, v, d);
}
ans.Maxflow(s, t);
for (int i = 1;i <= m;i++)
{
int u = U[i], v = V[i];
if (ans.a[u] > 0 && ans.a[v] <= 0 || ans.a[u] <= 0 && ans.a[v] > 0)
printf("%d %d\n", u, v);
}
puts("");
}
return 0;
}
L - Kakuro Extension
这题比较有意思,建图一开始想到了,但要么re要么wa,搞了好久。。没想到是最后输出的时候弄错了。
建图方式:源点连行,行连白点,白点连列,列连汇点即可。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
#include<vector>
#include<queue>
using namespace std;
const int maxv = 5e5;
const int inf = 0x3f3f3f3f;
struct Edge
{
int from, to, cap, flow;
Edge(int u, int v, int c, int f) :from(u), to(v), cap(c), flow(f) {}
Edge() {}
};
struct Dinic
{
int n, m, s, t;
vector<Edge>edges;
vector<int>G[maxv + 50];
bool vis[maxv + 50];
int d[maxv + 50];
int cur[maxv + 50];
void AddEdge(int from, int to, int cap)
{
edges.push_back(Edge(from, to, cap, 0));
edges.push_back(Edge(to, from, 0, 0));
m = edges.size();
G[from].push_back(m - 2);
G[to].push_back(m - 1);
}
void init(int n)
{
for (int i = 0;i <= n;i++)G[i].clear();
edges.clear();
}
bool BFS()
{
memset(vis, 0, sizeof(vis));
queue<int>Q;
Q.push(s);
d[s] = 0;
vis[s] = 1;
while (!Q.empty())
{
int x = Q.front();Q.pop();
for (int i = 0;i < G[x].size();i++)
{
Edge&e = edges[G[x][i]];
if (!vis[e.to] && e.cap > e.flow)
{
vis[e.to] = 1;
d[e.to] = d[x] + 1;
Q.push(e.to);
}
}
}
return vis[t];
}
int DFS(int x, int a)
{
if (x == t || a == 0)return a;
int flow = 0, f;
for (int &i = cur[x];i < G[x].size();i++)
{
Edge&e = edges[G[x][i]];
if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow)))>0)
{
e.flow += f;
edges[G[x][i] ^ 1].flow -= f;
flow += f;
a -= f;
if (a == 0)break;
}
}
return flow;
}
int Maxflow(int s, int t)
{
//cout << edges.size() << endl;
this->s = s;this->t = t;
int flow = 0;
while (BFS())
{
memset(cur, 0, sizeof(cur));
flow += DFS(s, inf);
}
return flow;
}
}ans;
char map[105][105][10];
int num[105][105][2];
int theid[105][105], ID;
int getnum(int x, int y, int begin)
{
int thenum = 0;
for (int i = begin;i < begin + 3;i++)
thenum = thenum * 10 + map[x][y][i] - '0';
return thenum;
}
int rows, cows;
int s, t;
int n, m;
int Add(int u,int x, int y, int tp)
{
if (tp == 0)
{
int tmpx = x + 1;
while (theid[tmpx][y] != 0)
{
ans.AddEdge(rows+theid[tmpx][y], u, 8);
tmpx++;
}
return tmpx - x-1;
}
if (tp == 1)
{
int tmpy = y + 1;
while (theid[x][tmpy]!=0)
{
ans.AddEdge(u, theid[x][tmpy]+rows, 8);
tmpy++;
}
return tmpy - y-1;
}
}
void buildmap()
{
s = 0, t = rows + cows + ID + 1;
ans.init(t);
int rtmp = 0, ctmp = 0;
for(int i=1;i<=n;i++)
for (int j = 1;j <= m;j++)
{
if (num[i][j][0])
{
ctmp++;
int use=Add(rows+ID+ctmp,i, j, 0);
ans.AddEdge(rows + ID + ctmp, t, num[i][j][0]-use);
}
if (num[i][j][1])
{
rtmp++;
int use=Add(rtmp, i, j, 1);
ans.AddEdge(s, rtmp, num[i][j][1]-use);
}
}
}
int Ansmap[105][105];
int X[maxv], Y[maxv];
int main()
{
while (~scanf("%d %d", &n, &m))
{
rows = cows = ID=0;
memset(num, 0, sizeof(num));
memset(theid, 0, sizeof(theid));
for (int i = 1;i <= n;i++)
for (int j = 1;j <= m;j++)
scanf("%s", map[i][j]);
int tmp;
for (int i = 1;i <= n;i++)
for (int j = 1;j <= m;j++)
{
if (map[i][j][0] != 'X'&&map[i][j][0] != '.')
{
cows++;
tmp = getnum(i, j, 0);
num[i][j][0] = tmp;
}
if (map[i][j][4] != 'X'&&map[i][j][4] != '.')
{
rows++;
tmp = getnum(i, j, 4);
num[i][j][1] = tmp;
}
else if (map[i][j][0] == '.')
theid[i][j] = ++ID, X[ID] = i, Y[ID] = j;
}
buildmap();
ans.Maxflow(s, t);
int Size = ans.edges.size();
for (int i = 0;i < Size;i+=2)
{
Edge &e = ans.edges[i];
if (e.from <= rows&&e.from!=0)
{
int to = e.to;
Ansmap[X[to - rows]][Y[to - rows]] = e.flow;
}
}
for (int i = 1;i <= n;i++)
{
for (int j = 1;j <= m;j++)
{
if (map[i][j][0] == '.')
printf("%d", Ansmap[i][j] + 1);
else
printf("_");
if (j != m)printf(" ");
}
printf("\n");
}
}
return 0;
}
M - Escape
一开始以为这题是个裸题,没想到还是有点技巧在里面。因为n为1e5,所以要么会T,要么会mle。。那么怎么做呢?由于m很少,所以一个人的选择顶多有
210
个状态。所以我们可以把人进行缩点,想清楚这个就和普通的多重匹配没啥区别了。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
#include<vector>
#include<queue>
using namespace std;
const int maxv = 1500;
const int inf = 0x3f3f3f3f;
struct Edge
{
int from, to, cap, flow;
Edge(int u, int v, int c, int f) :from(u), to(v), cap(c), flow(f) {}
Edge() {}
};
struct Dinic
{
int n, m, s, t;
vector<Edge>edges;
vector<int>G[maxv + 50];
bool vis[maxv + 50];
int d[maxv + 50];
int cur[maxv + 50];
void AddEdge(int from, int to, int cap)
{
edges.push_back(Edge(from, to, cap, 0));
edges.push_back(Edge(to, from, 0, 0));
m = edges.size();
G[from].push_back(m - 2);
G[to].push_back(m - 1);
}
void init(int n)
{
for (int i = 0;i <= n;i++)G[i].clear();
edges.clear();
}
bool BFS()
{
memset(vis, 0, sizeof(vis));
queue<int>Q;
Q.push(s);
d[s] = 0;
vis[s] = 1;
while (!Q.empty())
{
int x = Q.front();Q.pop();
for (int i = 0;i < G[x].size();i++)
{
Edge&e = edges[G[x][i]];
if (!vis[e.to] && e.cap > e.flow)
{
vis[e.to] = 1;
d[e.to] = d[x] + 1;
Q.push(e.to);
}
}
}
return vis[t];
}
int DFS(int x, int a)
{
if (x == t || a == 0)return a;
int flow = 0, f;
for (int &i = cur[x];i < G[x].size();i++)
{
Edge&e = edges[G[x][i]];
if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow)))>0)
{
e.flow += f;
edges[G[x][i] ^ 1].flow -= f;
flow += f;
a -= f;
if (a == 0)break;
}
}
return flow;
}
int Maxflow(int s, int t)
{
//cout << edges.size() << endl;
this->s = s;this->t = t;
int flow = 0;
while (BFS())
{
memset(cur, 0, sizeof(cur));
flow += DFS(s, inf);
}
return flow;
}
}ans;
int id[1500];
int tot;
void build(int theid,int a,int c)
{
int tmp;
int now = 0;
while (a)
{
tmp = a % 2;
a /= 2;
now++;
if (tmp)
ans.AddEdge(theid, tot + now, c);
}
}
int main()
{
int n, m;
int s, t;
while (~scanf("%d %d", &n, &m))
{
memset(id, 0, sizeof(id));
int tmp;
for (int i = 1;i <= n;i++)
{
int num = 0;
for (int j = 1;j <= m;j++)
{
scanf("%d", &tmp);
num = 2 * num + tmp;
}
id[num]++;
}
tot = 0;
for (int i = 0;i < 1500;i++)if (id[i])
tot++;
s = 0, t = tot + m + 1;
ans.init(t);
tmp = 0;
for (int i = 0;i < 1500;i++)if(id[i])
{
tmp++;
ans.AddEdge(s, tmp, id[i]);
build(tmp,i,id[i]);
}
for (int i = 1;i <= m;i++)
{
scanf("%d", &tmp);
ans.AddEdge(i + tot, t, tmp);
}
tmp = ans.Maxflow(s, t);
if (tmp == n)puts("YES");
else puts("NO");
}
return 0;
}
N - Marriage Match II
这题如何建图一开始并没有想到。。之后看了题解才恍然大悟。男孩和女孩直接的建图就直接按照题目要求建,然后再给一个源点连向所有女孩,容量为轮数,看最终最大流是否等于轮数*n即可。所以二分轮数就行了。
#include<iostream>
#include<cstring>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int maxv = 250;
const int inf = 0x3f3f3f3f;
struct Edge
{
int from, to, cap, flow;
Edge(int u, int v, int c, int f) :from(u), to(v), cap(c), flow(f) {}
Edge() {}
};
struct Dinic
{
int n, m, s, t;
vector<Edge>edges;
vector<int>G[maxv + 50];
bool vis[maxv + 50];
int d[maxv + 50];
int cur[maxv + 50];
void AddEdge(int from, int to, int cap)
{
edges.push_back(Edge(from, to, cap, 0));
edges.push_back(Edge(to, from, 0, 0));
m = edges.size();
G[from].push_back(m - 2);
G[to].push_back(m - 1);
}
void init(int n)
{
for (int i = 0;i <= n;i++)G[i].clear();
edges.clear();
}
bool BFS()
{
memset(vis, 0, sizeof(vis));
queue<int>Q;
Q.push(s);
d[s] = 0;
vis[s] = 1;
while (!Q.empty())
{
int x = Q.front();Q.pop();
for (int i = 0;i < G[x].size();i++)
{
Edge&e = edges[G[x][i]];
if (!vis[e.to] && e.cap > e.flow)
{
vis[e.to] = 1;
d[e.to] = d[x] + 1;
Q.push(e.to);
}
}
}
return vis[t];
}
int DFS(int x, int a)
{
if (x == t || a == 0)return a;
int flow = 0, f;
for (int &i = cur[x];i < G[x].size();i++)
{
Edge&e = edges[G[x][i]];
if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow)))>0)
{
e.flow += f;
edges[G[x][i] ^ 1].flow -= f;
flow += f;
a -= f;
if (a == 0)break;
}
}
return flow;
}
int Maxflow(int s, int t)
{
//cout << edges.size() << endl;
this->s = s;this->t = t;
int flow = 0;
while (BFS())
{
memset(cur, 0, sizeof(cur));
flow += DFS(s, inf);
}
return flow;
}
}ans;
int s, t;
pair<int, int>pii[10005];
bool map[105][105];
int fa[105];
int find(int a) { return a == fa[a] ? a : fa[a] = find(fa[a]); }
int n, m, f;
bool check(int num)
{
ans.init(t);
for (int i = 1;i <= n;i++)
ans.AddEdge(s, i, num),ans.AddEdge(i+n,t,num);
for (int i = 1;i <= m;i++)
{
int u = pii[i].first, v = pii[i].second;
ans.AddEdge(u, n + v, 1);
int fu = find(u);
for (int j = 1;j <= n;j++)if(j!=u)
{
int fj = find(j);
if (fj == fu&&map[j][v] == 0)
{
ans.AddEdge(j, n + v, 1);
}
}
}
if (ans.Maxflow(s, t) == num*n)return 1;
return 0;
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
memset(map, 0, sizeof(map));
scanf("%d %d %d", &n, &m, &f);
s = 0, t = 2 * n + 1;
for (int i = 1;i <= n;i++)
fa[i] = i;
int u, v;
for (int i = 1;i <= m;i++)
{
scanf("%d %d", &u, &v);
map[u][v] = 1;
pii[i] = make_pair(u, v);
}
for (int i = 1;i <= f;i++)
{
scanf("%d %d", &u, &v);
int fu = find(u), fv = find(v);
if (fu != fv)
fa[fu] = fv;
}
int l = 0, r = n, tans = l;
int mid;
while (l<=r)
{
mid = l + r >> 1;
if (check(mid))
{
tans = mid;
l = mid + 1;
}
else
r = mid - 1;
}
printf("%d\n", tans);
}
return 0;
}
O - Marriage Match IV
最后一题之前在最短路出现过,但做的时候并没有想起来,想了一会才知道怎么建图。感觉题挺好的还是贴上来吧。首先我们得求出哪些边在最短路中,然后根据这些边重新建个图,容量为1跑最大流就行了。怎么知道边在最短路中呢,跑两边dijkstra即可。
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
const int maxn = 1005;
const int maxm = 100005;
const int maxv = 1005;
const int inf = 0x3f3f3f3f;
struct Edge1
{
int u, v, dist, next;
Edge1(int _u,int _v,int _d,int _nxt):u(_u),v(_v),dist(_d),next(_nxt){}
Edge1(){}
}edges1[maxm], edges2[maxm];
struct HeapNode
{
int u, d;
HeapNode(int _u,int _d):u(_u),d(_d){}
HeapNode(){}
bool operator<(const HeapNode &b)const
{
return d > b.d;
}
};
int head1[maxn], tot1;
int head2[maxn], tot2;
int n, m;
void addedge(int u, int v, int d,Edge1 *edges, int *head,int &tot)
{
edges[tot] = Edge1(u, v, d, head[u]);
head[u] = tot++;
}
int d1[maxn], d2[maxn];
bool vis[maxn];
void dijkstra(int s, int *d, Edge1 *edges, int *head)
{
for (int i = 1;i <= n;i++)
d[i] = inf;
d[s] = 0;
priority_queue<HeapNode>Q;
Q.push(HeapNode(s,d[s]));
memset(vis, 0, sizeof(vis));
while (!Q.empty())
{
HeapNode x = Q.top();Q.pop();
if (vis[x.u])continue;
vis[x.u] = 1;
for (int i = head[x.u];~i;i = edges[i].next)
{
Edge1 &e = edges[i];
if (d[e.v] > d[x.u] + e.dist)
{
d[e.v] = d[x.u] + e.dist;
Q.push(HeapNode(e.v, d[e.v]));
}
}
}
}
struct Edge
{
int from, to, cap, flow;
Edge(int u, int v, int c, int f) :from(u), to(v), cap(c), flow(f) {}
Edge() {}
};
struct Dinic
{
int n, m, s, t;
vector<Edge>edges;
vector<int>G[maxv + 50];
bool vis[maxv + 50];
int d[maxv + 50];
int cur[maxv + 50];
void AddEdge(int from, int to, int cap)
{
edges.push_back(Edge(from, to, cap, 0));
edges.push_back(Edge(to, from, 0, 0));
m = edges.size();
G[from].push_back(m - 2);
G[to].push_back(m - 1);
}
void init(int n)
{
for (int i = 0;i <= n;i++)G[i].clear();
edges.clear();
}
bool BFS()
{
memset(vis, 0, sizeof(vis));
queue<int>Q;
Q.push(s);
d[s] = 0;
vis[s] = 1;
while (!Q.empty())
{
int x = Q.front();Q.pop();
for (int i = 0;i < G[x].size();i++)
{
Edge&e = edges[G[x][i]];
if (!vis[e.to] && e.cap > e.flow)
{
vis[e.to] = 1;
d[e.to] = d[x] + 1;
Q.push(e.to);
}
}
}
return vis[t];
}
int DFS(int x, int a)
{
if (x == t || a == 0)return a;
int flow = 0, f;
for (int &i = cur[x];i < G[x].size();i++)
{
Edge&e = edges[G[x][i]];
if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow)))>0)
{
e.flow += f;
edges[G[x][i] ^ 1].flow -= f;
flow += f;
a -= f;
if (a == 0)break;
}
}
return flow;
}
int Maxflow(int s, int t)
{
//cout << edges.size() << endl;
this->s = s;this->t = t;
int flow = 0;
while (BFS())
{
memset(cur, 0, sizeof(cur));
flow += DFS(s, inf);
}
return flow;
}
}ans;
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
tot1 = tot2 = 0;
memset(head1, -1, sizeof(head1));
memset(head2, -1, sizeof(head1));
scanf("%d %d", &n, &m);
int u, v, d;
for (int i = 1;i <= m;i++)
{
scanf("%d %d %d", &u, &v, &d);
if (u == v)continue;
addedge(u, v, d, edges1, head1, tot1);
addedge(v, u, d, edges2, head2, tot2);
}
int s, t;
scanf("%d %d", &s, &t);
dijkstra(s, d1, edges1, head1);
dijkstra(t, d2, edges2, head2);
ans.init(n);
int minst = d1[t];
for (int i = 0;i < tot1;i++)
{
Edge1 &e = edges1[i];
if (d1[e.u] + d2[e.v] + e.dist == minst)
ans.AddEdge(e.u, e.v, 1);
}
printf("%d\n", ans.Maxflow(s, t));
}
return 0;
}