题目:

 

 

 

分析:

像这种,有两种颜色,还是方阵,数据范围还那么小,首选二分图匹配。

通过分析题目,可以知道,无论怎么交换,一行或一列的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

 

posted on 2019-10-13 15:42  rua-rua-rua  阅读(168)  评论(0编辑  收藏  举报