传送门
题意:给你行列的个数,然后给你每行Y的个数,每列Y的个数,看是否有符合条件的由NY构成的矩阵,有的话输出,要求字典序最小的那个。
思路:最大流问题,首先可以建立超级源点,将源点向代表行的点建立边,容量为该行的Y数量,然后行点向列点建边,每对都建立容量为1的边,最后建立列点到超级汇点的边,容量为该列的Y个数。
上述是建图方法,解此题时,要先统计行上Y的总和,列上Y的总和,若相等才建图,否则直接不可能。
求一遍最大流后,若流量不等于Y的总数,那也不可能。
上述如果都符合,那么就是存在,之后考虑其最小字典序问题。这里采用枚举的办法。先从第一行看起,第一个逐个往后看,若i行到j列的边没流量,这里就确定是N,并将其容量改为0;若满流,则判断若不经过这条边能否再找到一条增广路(由于前面没流量的边已改为流量0,所以只可能出现在之后的边),如果能,则这为N,否则只能是Y,从而保证了字典序。
心得:自己还是too young,这题卡了那么好几天才过。
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #define maxn 1<<29 using namespace std; int fst[2220],next[111101],node[111101],c[111101],en; int f[111101],pre[2220],lu[2200]; int m,n,s,t,snum,tnum,a[111],b[111]; bool p[222][222],vis[2220]; int ed[1110][1110],id[2220]; bool block[10000]; int dis[22200]; int q[1111111]; void init() { en=0; snum=0; tnum=0; s=0; t=m+n+1; memset(fst,-1,sizeof(fst)); } void add(int u,int v,int w) { next[en]=fst[u]; fst[u]=en; node[en]=v; c[en]=w; en++; } void lays() { int q[3000],front=0,end=0; for(int i=s; i<=t; i++)dis[i]=maxn; q[end++]=s; dis[s]=0; while(front<end) { int u=q[front++]; for(int i=fst[u]; i!=-1; i=next[i]) { int v=node[i]; if(dis[v]==maxn&&c[i]>f[i]) { dis[v]=dis[u]+1; q[end++]=v; } } } } int dinic() { int flow=0; memset(f,0,sizeof(f)); memset(block,0,sizeof(block)); //memset(low,0,sizeof(low)); lays(); int top=s; while(dis[t]!=maxn) { bool flag=false; //low[s]=maxn; int i,v; for(i=fst[top]; i!=-1; i=next[i]) { v=node[i]; if(c[i]>f[i]&&dis[v]==dis[top]+1&&!block[v]) { flag=true; break; } } if(flag) { //low[v]=c[i]-f[i]; //if(low[v]>low[top])low[v]=low[top]; pre[v]=top; top=v; lu[v]=i; if(top==t) { flow+=1; int j=top; while(j!=s) { int k=lu[j]; f[k]+=1; f[k^1]-=1; j=pre[j]; } top=s; //memset(low,0,sizeof(low)); } } else { block[top]=1; if(top!=s)top=pre[top]; } if(block[s]) { lays(); memset(block,0,sizeof(block)); } } return flow; } bool bfs() { memset(vis,0,sizeof(vis)); int front=0,end=0;; q[end++]=s; vis[s]=1; while(end>front) { int u=q[front++]; for(int i=fst[u]; i!=-1; i=next[i]) { int v=node[i]; if(c[i]>f[i]&&!vis[v]) { vis[v]=1; pre[v]=u; lu[v]=i; if(v==t)return true; q[end++]=v; } } } return false; } void solve() { int flow=dinic(); if(flow==tnum) { for(int i=1; i<=m; i++) { for(int j=1; j<=n; j++) { int u=ed[i][j]; if(f[u]) { c[u]=0; f[id[i]]--; f[id[j+m]]--; if(bfs()) { for(int k=t; k!=s; k=pre[k]) { int v=lu[k]; f[v]++; f[v^1]--; } } else { c[u]=1; f[id[i]]++; f[id[j+m]]++; } } else c[u]=0; } } memset(p,0,sizeof(p)); for(int i=1;i<=m;i++) { for(int j=fst[i];j!=-1;j=next[j]) { int v=node[j]; if(c[j]&&v-m>0)p[i][v-m]=1; } } for(int i=1;i<=m;i++) { for(int j=1;j<=n;j++) { if(p[i][j])putchar('Y'); else putchar('N'); } puts(""); } } else { cout<<"Impossible"<<endl; } } int main() { int ca=1; while(scanf("%d%d",&m,&n)!=EOF) { if(m==0&&n==0)break; init(); for(int i=1;i<=m;i++) { scanf("%d",&a[i]); snum+=a[i]; } for(int i=1;i<=n;i++) { scanf("%d",&b[i]); tnum+=b[i]; } if(ca!=1)cout<<endl; ca++; if(tnum!=snum) { cout<<"Impossible"<<endl; continue; } for(int i=1;i<=m;i++) { id[i]=en; add(0,i,a[i]); add(i,0,0); } for(int i=1;i<=n;i++) { id[i+m]=en; add(m+i,m+n+1,b[i]); add(m+n+1,m+i,0); } for(int i=1;i<=m;i++) { for(int j=1;j<=n;j++) { ed[i][j]=en; add(i,m+j,1); add(m+j,i,0); } } solve(); } return 0; }