题目链接:
题意:
给一个矩阵的每行和每列的和,(给的是前i行或者列的和);
矩阵中每个元素的值在1到20之间,找出这样的一个矩阵;
思路:
把它转化成一个二分图,每行和每列之间连一条弧,然后设置一个源点和一个汇点,源点与行点相连,汇点与列点相连,求一个最大值,当然这是一个有下界的最大流,需要做-1的处理,同时与源汇相连的边也是要处理的;最后求得的反向边+1就是答案了;
AC代码:
#include <bits/stdc++.h> /*#include <iostream> #include <queue> #include <cmath> #include <cstring> #include <algorithm> #include <cstdio> */ using namespace std; #define Riep(n) for(int i=1;i<=n;i++) #define Riop(n) for(int i=0;i<n;i++) #define Rjep(n) for(int j=1;j<=n;j++) #define Rjop(n) for(int j=0;j<n;j++) #define mst(ss,b) memset(ss,b,sizeof(ss)); typedef long long LL; const LL mod=1e9+7; const double PI=acos(-1.0); const int inf=0x3f3f3f3f; const int N=1e5+25; int n,m,a[45],b[45],cap[45][45],path[45],flow[45]; queue<int>qu; int bfs() { mst(path,-1); flow[0]=inf; path[0]=0; qu.push(0); while(!qu.empty()) { int fr=qu.front(); qu.pop(); for(int i=1;i<=n+m+1;i++) { if(path[i]==-1&&cap[fr][i]) { flow[i]=min(cap[fr][i],flow[fr]); path[i]=fr; qu.push(i); } } } if(path[n+m+1]==-1)return -1; return flow[n+m+1]; } void maxflow() { int now,pre; while(1) { int temp=bfs(); if(temp==-1)break; now=n+m+1; while(now!=0) { pre=path[now]; cap[pre][now]-=temp; cap[now][pre]+=temp; now=pre; } } } int main() { int t,Case=1; scanf("%d",&t); while(Case<=t) { mst(cap,0); scanf("%d%d",&n,&m); Riep(n)scanf("%d",&a[i]); Riep(n) { cap[0][i]=a[i]-a[i-1]-m; } Riep(m)scanf("%d",&b[i]); Riep(m) { cap[i+n][n+m+1]=b[i]-b[i-1]-n; } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cap[i][j+n]=19; maxflow(); printf("Matrix %d ",Case++); Riep(n) { Rjep(m-1) printf("%d ",cap[j+n][i]+1); printf("%d ",cap[m+n][i]+1); } printf(" "); } return 0; }