机房测试11&&12:矩阵游戏 && 象棋(二分图匹配)
作者:互联网
题目:
分析:
像这种,有两种颜色,还是方阵,数据范围还那么小,首选二分图匹配。
通过分析题目,可以知道,无论怎么交换,一行或一列的1的个数是不会改变的。
最后的要求是每行和每列至少要共用一个1,。
可以想象成:
行 位置 列
行通过有1的位置向列连边,从而达到一行匹配一列。
将中间的点去掉就是二分图匹配了,当且仅当匹配数==n时才合法。
#include<bits/stdc++.h> using namespace std; #define N 405 #define M 50005 #define ri register int int read() { int x=0,fl=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') fl=-1; ch=getchar(); } while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x*fl; } int a[N][N],n,ans=0,head[M],nex[M],to[M],tot=0,match[M],vis[M],Ti=0; void add(int a,int b) { to[++tot]=b; nex[tot]=head[a]; head[a]=tot; } bool dfs(int u) { if(vis[u]==Ti) return false; vis[u]=Ti; for(ri i=head[u];i;i=nex[i]){ int v=to[i]; if(!match[v] || dfs(match[v])){ match[v]=u; match[u]=v; return true; } } return false; } void init() { for(ri i=0;i<=max(tot,2*n);++i) head[i]=to[i]=nex[i]=match[i]=vis[i]=0; tot=0; Ti=0; ans=0; } int main() { freopen("f.in","r",stdin); freopen("f.out","w",stdout); int T=read(); while(T--){ init(); n=read(); for(ri i=1;i<=n;++i){ for(ri j=1;j<=n;++j){ a[i][j]=read(); if(a[i][j]) add(i,j+n),add(j+n,i);// } } for(ri i=1;i<=n;++i){ Ti++; ans+=dfs(i); } if(ans==n) printf("Yes\n"); else printf("No\n"); } return 0; } /* 6 2 0 0 0 1 3 0 0 1 0 1 0 1 0 0 4 0 0 0 1 0 0 1 0 1 0 0 0 0 1 1 0 */View Code
题目:
分析:
如果没有障碍的限制,直接按照上一道题的思路,行向列连边(一行只能放一个,一列只能放一个),跑一边二分图匹配。
多了障碍,对于行来说,相当于一行分成了很多个部分,每个部分都可以放一个,列也同理。
将行被分裂后的各个部分重新编号,与列连边即可。
最后答案就是最大匹配数。
(我用的是网络流)
#include<bits/stdc++.h> using namespace std; #define N 205 #define M 1000005 #define ri register int int n,m,a[N][N],h[N][N],l[N][N],id[N][N],s,t; char ss[N]; int cost[M],lev[M],head[M],nex[M<<1],to[M<<1],tot=1,hang,lie; queue<int> q; void add(int a,int b,int ww) { //printf("%d %d %d\n",a,b,ww); to[++tot]=b; nex[tot]=head[a]; head[a]=tot; cost[tot]=ww; to[++tot]=a; nex[tot]=head[b]; head[b]=tot; cost[tot]=0; } bool bfs() { memset(lev,-1,sizeof(lev)); lev[s]=0; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); for(int i=head[u];i!=-1;i=nex[i]) { int v=to[i]; if(cost[i]!=0&&lev[v]==-1) lev[v]=lev[u]+1,q.push(v); } } if(lev[t]!=-1) return true; return false; } int dfs1(int u,int flow) { if(u==t) return flow; int ret=flow; for(int i=head[u];i!=-1;i=nex[i]) { if(ret<=0) break; int v=to[i]; if(cost[i]&&lev[u]+1==lev[v]) { int k=dfs1(v,min(cost[i],ret)); ret-=k; cost[i]-=k; cost[i^1]+=k; } } return flow-ret; } void dinic() { int ans=0; while(bfs()) ans+=(dfs1(s,lie)); printf("%d\n",ans); } int main() { freopen("chess.in","r",stdin); freopen("chess.out","w",stdout); scanf("%d%d",&n,&m); memset(head,-1,sizeof(head)); s=0,t=n*m*4; int cnt=0; for(ri i=1;i<=n;++i){ scanf("%s",ss); for(ri j=1;j<=m;++j) a[i][j]=ss[j-1]-'0',id[i][j]=++cnt; } hang=0,lie=0; for(ri i=1;i<=n;++i) for(ri j=1;j<=m;++j) if(j==1) h[i][j]=a[i][j] ? 0 : ++hang; else if(a[i][j]==a[i][j-1] && a[i][j]==0) h[i][j]=h[i][j-1]; else if(a[i][j-1]==1 && a[i][j]==0) h[i][j]=++hang; else h[i][j]=0; for(ri j=1;j<=m;++j) for(ri i=1;i<=n;++i) if(i==1) l[i][j]=a[i][j] ? 0 : ++lie; else if(a[i][j]==a[i-1][j] && a[i][j]==0) l[i][j]=l[i-1][j]; else if(a[i-1][j]==1 && a[i][j]==0) l[i][j]=++lie; else l[i][j]=0; /*for(ri i=1;i<=n;++i){ for(ri j=1;j<=m;++j) cout<<h[i][j]<<" "; cout<<endl; } printf("lie:%d\n",hang);*/ for(ri i=1;i<=n;++i) for(ri j=1;j<=m;++j) if(a[i][j]==0) add(l[i][j]+n*m,id[i][j],1),add(id[i][j],h[i][j]+2*n*m,1); for(ri i=1;i<=lie;++i) add(s,i+n*m,1); for(ri i=1;i<=hang;++i) add(i+n*m*2,t,1); dinic(); } /* 3 3 010 001 010 */View Code
标签:11,head,12,&&,int,tot,ch,lev,define 来源: https://www.cnblogs.com/mowanying/p/11657258.html