题目大概有一个n*m的矩阵,已知各行所有数的和的前缀和和各列所有数的和的前缀和,且矩阵各个数都在1到20的范围内,求该矩阵的一个可能的情况。
POJ2396的弱化版本吧。。建图的关键在于:
- 把行、列看成点,各单元看成边
这个建图感觉非常巧。。
各个单元有下界限制。。这个我可不想再写带下界的最大流。。
想了下,发现可以用最小费用最大流求解:通过放大边的费用,使得这条边成为一条必须会被经过的边。
简单来说就是各单元代表的边拆成两条,一条容量1费用-1,另外一条容量19费用0。这样跑MCMF,显然为了让费用最小,所有费用-1的边必然会经过,这样就保证了各个单元的值至少为1。
(其实有个更简单的方法就是所有单元格都同时减去1。。)
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<algorithm> 5 using namespace std; 6 #define MAXN 44 7 #define MAXM 88*88 8 #define INF (1<<30) 9 10 struct Edge{ 11 int v,cap,cost,next; 12 }edge[MAXM]; 13 int vs,vt,NV,NE,head[MAXN]; 14 void addEdge(int u,int v,int cap,int cost){ 15 edge[NE].v=v; edge[NE].cap=cap; edge[NE].cost=cost; 16 edge[NE].next=head[u]; head[u]=NE++; 17 edge[NE].v=u; edge[NE].cap=0; edge[NE].cost=-cost; 18 edge[NE].next=head[v]; head[v]=NE++; 19 } 20 21 int d[MAXN],pre[MAXN]; 22 bool inque[MAXN]; 23 bool SPFA(){ 24 for(int i=0; i<NV; ++i){ 25 d[i]=INF; inque[i]=0; 26 } 27 d[vs]=0; inque[vs]=1; 28 queue<int> que; 29 que.push(vs); 30 while(!que.empty()){ 31 int u=que.front(); que.pop(); 32 for(int i=head[u]; i!=-1; i=edge[i].next){ 33 int v=edge[i].v; 34 if(edge[i].cap && d[v]>d[u]+edge[i].cost){ 35 d[v]=d[u]+edge[i].cost; 36 pre[v]=i; 37 if(!inque[v]){ 38 inque[v]=1; 39 que.push(v); 40 } 41 } 42 } 43 inque[u]=0; 44 } 45 return d[vt]!=INF; 46 } 47 int mxflow; 48 int MCMF(){ 49 mxflow=0; 50 int res=0; 51 while(SPFA()){ 52 int flow=INF,cost=0; 53 for(int u=vt; u!=vs; u=edge[pre[u]^1].v){ 54 flow=min(flow,edge[pre[u]].cap); 55 } 56 mxflow+=flow; 57 for(int u=vt; u!=vs; u=edge[pre[u]^1].v){ 58 edge[pre[u]].cap-=flow; 59 edge[pre[u]^1].cap+=flow; 60 cost+=edge[pre[u]].cost; 61 } 62 res+=cost*flow; 63 } 64 return res; 65 } 66 67 int row[22],col[22],ans[22][22]; 68 int main(){ 69 int t,n,m; 70 scanf("%d",&t); 71 for(int cse=1; cse<=t; ++cse){ 72 scanf("%d%d",&n,&m); 73 vs=0; vt=n+m+1; NV=vt+1; NE=0; 74 memset(head,-1,sizeof(head)); 75 for(int i=1; i<=n; ++i){ 76 scanf("%d",row+i); 77 addEdge(vs,i,row[i]-row[i-1],0); 78 } 79 for(int i=1; i<=m; ++i){ 80 scanf("%d",col+i); 81 addEdge(i+n,vt,col[i]-col[i-1],0); 82 } 83 for(int i=1; i<=n; ++i){ 84 for(int j=1; j<=m; ++j){ 85 addEdge(i,j+n,1,-1); 86 addEdge(i,j+n,19,0); 87 } 88 } 89 MCMF(); 90 memset(ans,0,sizeof(ans)); 91 for(int u=1; u<=n; ++u){ 92 for(int i=head[u]; i!=-1; i=edge[i].next){ 93 if(i&1) continue; 94 int v=edge[i].v-n; 95 ans[u][v]+=edge[i^1].cap; 96 } 97 } 98 if(cse!=1) putchar(' '); 99 printf("Matrix %d ",cse); 100 for(int i=1; i<=n; ++i){ 101 for(int j=1; j<=m; ++j){ 102 printf("%d ",ans[i][j]); 103 } 104 putchar(' '); 105 } 106 } 107 return 0; 108 }