传送门
给出每一个城市的初始人数,以及期望人数,每个人最多只能走一步。最后告诉城市的连接情况。
如果可以,就输出yes,在输出(n^2)的矩阵,(i = j)时,输出第(i)个城市需要留几个人。否则输出(i)城市到(j)城市需要走几个人。
建立一个超级源点和一个超级汇点,
超级源点连接所有的城市,边权是(a_i),对于每一个城市再构建虚拟城市,与超级汇点连接,边权是(b_i)
再把每一个城市和它的虚拟城市连接,边权是无穷大。
再按照题目给的连接情况进行建边,边权是无穷大。
然后跑最大流即可
关于匹配情况,可以通过他的反向边来看,因为匹配时其实就3个点,那么反向边就是这个城市到那个城市的人数。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define ll long long
using namespace std;
const int N = 200 + 5;
const int M = 5e3 + 5;
const int inf = 0x3f3f3f3f;
template<typename T = long long> inline T read() {
T s = 0, f = 1; char ch = getchar();
while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
while(isdigit(ch)) {s = (s << 3) + (s << 1) + ch - 48; ch = getchar();}
return s * f;
}
namespace MAX_FLOW {
const int N = 200 + 5;
int st, ed;
struct Edge{
int from, to, next, w;
}e[M << 1];
int head[N], tot = 1, cur[N]; //弧优化
void add(int u, int v, int w){
e[++tot].to = v;
e[tot].from = u;
e[tot].w = w;
e[tot].next = head[u];
head[u] = tot;
}
void add_edge(int u, int v, int w){
add(u, v, w), add(v, u, 0);
}
int dis[N];
int dfs(int u, int flow){ //保证了每次DFS都能找到增广路
if(u == ed) return flow;
int sum = 0;
for(int i = cur[u]; i && flow; i = e[i].next){
cur[u] = i;
int v = e[i].to, w = e[i].w;
if(w > 0 && dis[v] == dis[u] + 1){
int t = dfs(v, min(flow, w)); //获取这条增广路的最小流量
e[i].w -= t; e[i ^ 1].w += t; //减去最小流量,同时反向边加上最小流量
flow -= t; sum += t;
}
}
if(!sum) dis[u] = 0;//结果u无法到达终点,或者没有增广路,切断经过这个点的路径
return sum;
}
bool bfs(){//分层判断是否有增广路
memset(dis, 0, sizeof(dis));
queue<int> q;
q.push(st); dis[st] = 1; cur[st] = head[st];//弧优化
while(!q.empty()){
int u = q.front(); q.pop();
for(int i = head[u]; i; i = e[i].next){
int v = e[i].to, w = e[i].w;
if(w > 0 && !dis[v]) {
cur[v] = head[v];// v这个点从head[v]出发是可行的
dis[v] = dis[u] + 1;//分层
q.push(v);
if(v == ed) return 1;//已经到达增广路,直接返回
}
}
}
return dis[ed];
}
ll Dinic(){
ll max_flow = 0;
while(bfs())
max_flow += dfs(st, inf);
return max_flow;
}
};
int a[N], b[N];
int ans[N][N];
int main(){
int n = read(), m = read(); int s = 0, t = 2 * n + 1;
MAX_FLOW::st = s, MAX_FLOW::ed = t;
int sum1 = 0, sum2 = 0;
for(int i = 1; i <= n; i++) a[i] = read(), MAX_FLOW::add_edge(s, i, a[i]), sum1 += a[i];
for(int i = 1; i <= n; i++) b[i] = read(), MAX_FLOW::add_edge(i + n, t, b[i]), sum2 += b[i];
for(int i = 1; i <= n; i++) MAX_FLOW::add_edge(i, i + n, inf);
for(int i = 1; i <= m; i++) {
int u = read(), v = read();
MAX_FLOW::add_edge(u, v + n, inf);
MAX_FLOW::add_edge(v, u + n, inf);
}
if(sum1 != sum2) {
printf("NO
"); return 0;
}
ll max_flow = MAX_FLOW::Dinic();
if(sum2 != max_flow) {
printf("NO
"); return 0;
}
for(int i = 4 * n + 2; i <= MAX_FLOW::tot; i += 2) {
if(MAX_FLOW::e[i ^ 1].w) ans[MAX_FLOW::e[i].from][MAX_FLOW::e[i].to - n] = inf - MAX_FLOW::e[i].w;
}
printf("YES
");
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
printf("%d%c", ans[i][j], "
"[j == n]);
return 0;
}