2. B - Matrix Decompressing
题意:定义一个R*C的正整数矩阵(1<=R,C<=20),设Ai为前i行所有元素之和,Bi为前i列所有元素之和。
题目已知R,C和数组A,B。要找一个满足条件的矩阵。矩阵中的元素要满足(1<=X[i][j]<=20)。
思路:
根据a,b数组求出每一行的元素之和a,每一列的元素之和b 建一个源点s=0,汇点t=R+C+1
然后每一行看成一个顶点1~R,每一列看成一个顶点R+1~R+C
矩阵中每一个位置看成是一条边,比如2行3列的点,就是连接第2行和第3列的点的边。 然后从s到每一行建一条边,容量为a[i],
从每一列到t建一条边,容量为b[i] 然后每一行的点向每一列的点建边,容量为20(暂且说是20,继续看下去,20是错的,19才是对的)
这样的图的意义: 整个矩阵的和代表总的流量 从s出发,分别流向R行(所以有a1+…+a[R]=总流量)
每一行的流量会分给该行的C个元素,每一个列的顶点会从R行获得总的流量,就是该列的流量,最后流到t的总流量还是s出发的流量。
所以行的顶点和列的顶点的R*C条边流过的流量就代表矩阵中R*C个位置的值。
因为题目要求矩阵的位置的值在1~20之间,
所以R*C条边的流量应该在1~20之间,所以R*C条边的最大流量即容量就是20.
但是这样是有问题的,我们好像忽略了一个问题,如果某一条边没有流量怎么办?
某一条边流量为0的情况下,就不能满足矩阵中的元素在1~20之间了
可以先给所有的边给一个值为1的流量,这样的话条件就改成了1~19 了。
求到的最后流量值+1就是矩阵中的元素值。
解决代码:
#include<bits/stdc++.h>
#define maxn 1000
#define INF (1<<31)-1
using namespace std;
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 Dinic
{
int n,m,s,t;
vector<Edge> edges;
vector<int> G[maxn];
int d[maxn];
int cur[maxn];
bool vis[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,0,0));
m = edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
bool BFS()
{
memset(vis,false,sizeof(vis));
for (int i=0; i<n; i++) d[i] = INF;
d[s] = 0; vis[s] = true;
queue<int> Q;
Q.push(s);
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] = true;
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[e.to] == d[x]+1 && (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;
}
bool OKA()
{
for (int i=0; i<G[s].size(); i++)
{
Edge e = edges[G[s][i]];
if (e.cap!=e.flow)
return false;
}
return true;
}
bool OKB(int R,int C)
{
for (int j=R+1; j<=R+C; j++)
{
Edge& e = edges[G[j][0]];
if (e.cap!=e.flow)
return false;
}
return true;
}
void Maxflow(int t,int R,int C)
{
int flow = 0;
while (BFS())
{
memset(cur,0,sizeof(cur));
flow += DFS(s,INF);
}
cout<<"Matrix "<<t<<endl;
if (OKA() && OKB(R,C))
{
for (int i=1; i<=R; i++)
{
int j;
for (j=1; j<G[i].size()-1; j++)
cout<<edges[G[i][j]].flow+1<<' ';
cout<<edges[G[i][j]].flow+1<<endl;
}
}
cout<<endl;
}
};
int main()
{
Dinic aa;
int T,R,C,tmp;
int a[30],b[30],c[30],d[30];
#ifndef ONLINE_JUDGE
freopen("1.in", "r", stdin);
freopen("1.out", "w", stdout);
#endif
cin>>T;
tmp = T;
while (T>0)
{
T--;
aa.init(maxn);
cin>>R>>C;
for (int i=1; i<=R; i++) cin>>a[i];
for (int i=1; i<=C; i++) cin>>b[i];
for (int i=1; i<=R; i++) c[i] = a[i]-a[i-1]-C;
for (int i=1; i<=C; i++) d[i] = b[i]-b[i-1]-R;
for (int i=1; i<=R; i++)
aa.Addedge(0,i,c[i]);
for (int i=1; i<=C; i++)
aa.Addedge(R+i,R+C+1,d[i]);
for (int i=1; i<=R; i++)
for (int j=1; j<=C; j++)
aa.Addedge(i,R+j,19);
aa.s = 0; aa.t = R+C+1;
aa.Maxflow(tmp-T,R,C);
}
return 0;
}