题目大意
对于一个R行C列的正整数矩阵(1 <= R, C <= 20),设AiA_iAi为前i行所有元素之和,BiB_iBi
为前i列所有元素之和。已知R,C和数组A和B,找一个满足条件的矩阵。矩阵中的元素必须是1~20之间的正整数。
思路
建图方法,设一个超级源点S与超级汇点TO,然后S连每一行容量为这一行的和-1,然后每一列连TO的容量为这一列的和-1,然后每一行连每一列容量为19,然后跑一个最大流
EK算法代码
好处是代码好写,坏处是效率不高
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 50;
int c[maxn][maxn];
int f[maxn][maxn];
int a[maxn]; // 当前点到i的可改进量
int p[maxn];
int R, C, n;
int EK(int s, int t) {
memset(p,0,sizeof(p));
memset(f,0,sizeof(f));
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 to = 0; to < n; to++) {
if(x == to) continue;
if(!a[to] && c[x][to] > f[x][to]) {
p[to] = x;
a[to] = min(a[x], c[x][to]-f[x][to]);
Q.push(to);
}
}
if(a[t]) break;
}
if(!a[t]) break;
for(int u = t; u != s; u = p[u]) {
f[p[u]][u]+=a[t];
f[u][p[u]]-=a[t];
}
flow+=a[t];
}
return flow;
}
int main() {
//freopen("/Users/maoxiangsun/MyRepertory/input.txt", "r", stdin);
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int T;cin>>T;
int cas = 0;
while(T--) {
memset(c, 0, sizeof(c));
cin>>R>>C;
cout << "Matrix " << ++cas << endl;
int tmp = 0;
for(int i = 1; i <= R; i++) {
int sum; cin >> sum;
c[0][i] = sum - tmp - C;
tmp = sum;
}
tmp = 0;
int TO = R+C+1; n = TO + 1;
int S = 0;
for(int i = 1; i <= C; i++) {
int sum; cin >> sum;
c[i+R][TO] = sum - tmp - R;
tmp = sum;
}
for(int i = 1; i <= R; i++) {
for(int j = 1; j <= C; j++) {
c[i][j+R] = 19;
}
}
EK(S,TO);
for(int i = 1; i <= R; i++) {
for(int j = 1; j <= C; j++) {
cout<<f[i][j+R]+1;
if(j==C) cout<<endl;
else cout<<" ";
}
}
if(T) printf("\n");
}
return 0;
}
dinic 算法
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 50;
const int inf = 0x3f3f3f3f;
int R, C;
int ans[22][22];
struct Dinic {
struct Edge {
int from, to, cap, flow;
};
int s,t;
vector<Edge> edges;
vector<int> G[maxn];
int d[maxn];
bool vis[maxn];
int cur[maxn];
void addEdge(int from, int to, int cap) {
edges.push_back((Edge){from,to,cap,0});
edges.push_back((Edge){to,from,0,0});
int tt = (int)edges.size();
G[from].push_back(tt-2);
G[to].push_back(tt-1);
}
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 MF(int s, int t) {
this->s = s; this->t = t;
int flow = 0;
while(BFS()) {
memset(cur, 0, sizeof(cur));
flow += DFS(s, inf);
}
return flow;
}
void init() {
edges.clear();
for(int i = 0; i <= R+C+2; i++) G[i].clear();
}
void getans() {
for(int i = 1; i <= R; i++) {
for(int j = 0; j < G[i].size(); j++) {
int to = edges[G[i][j]].to;
if(to) ans[i][to-R] = edges[G[i][j]].flow + 1;
}
}
}
}dinic;
int main() {
// freopen("/Users/maoxiangsun/MyRepertory/input.txt", "r", stdin);
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int T;cin>>T;
int cas = 0;
while(T--) {
cin>>R>>C;
dinic.init();
cout << "Matrix " << ++cas << endl;
int tmp = 0;
for(int i = 1; i <= R; i++) {
int sum; cin >> sum;
dinic.addEdge(0, i, sum-tmp-C);
tmp = sum;
}
tmp = 0;
int TO = R+C+1;
int S = 0;
for(int i = 1; i <= C; i++) {
int sum; cin >> sum;
dinic.addEdge(i+R, TO, sum-tmp-R);
tmp = sum;
}
for(int i = 1; i <= R; i++) {
for(int j = 1; j <= C; j++) {
dinic.addEdge(i, j+R, 19);
}
}
dinic.MF(S, TO);
dinic.getans();
for(int i = 1; i <= R; i++) {
for(int j = 1; j <= C; j++) {
cout<<ans[i][j];
if(j==C) cout<<endl;
else cout<<" ";
}
}
if(T) printf("\n");
}
return 0;
}
本文探讨了如何使用最大流算法解决矩阵构造问题,通过EK算法和Dinic算法实现矩阵元素的合理分配,确保矩阵满足特定行和列的元素和约束。
473

被折叠的 条评论
为什么被折叠?



