• UVALive 5903 Piece it together(二分图匹配)


    给你一个n*m的矩阵,每个点为'B'或'W'或'.'。然后你有一种碎片。碎片可以旋转,问可否用这种碎片精确覆盖矩阵。N,M<=500

    WB  《==碎片

      W

    题目一看,感觉是精确覆盖(最近被覆盖洗脑了),但是仔细分析可以知道,DLX精确覆盖不是正解。因为N*M=250,000远超出DLX的可行规模(数百吧,我猜)。

    然后感觉是贪心或者是抑或的什么的。。。。

    看了别人的代码,发现是最大匹配。。。然后就想。。。。对哦=。=其实黑点连2个白点就是匹配呀。。。。

    不得不说网络流构图还是挺有趣的,如果你会构的话。。。。

     

    首先,如果NB*2!=NW,那必然是NO,此处特判。

    构图是这样,每个黑点拆分成2个,一个只连接左右邻接的白点,一个只连接上下邻接的白点。然后就匹配了=。=

    规模分析:250,000/3*2=166,666个黑点(黑点拆分翻倍),250,000/3*2=166,666个白点。边有166,666*2=333,332条。。

     

    一开始写完这题是TLE...然后改了5处从>30sec变成100ms,还是有点收获的。。。

    ①如果某一个黑点匹配的那个match返回0而不是1,说明有黑点没匹配到,可直接break;结果为NO。。。。>30sec ==> 27sec,TLE==>AC

    ②将maxn的500,000改成180,000,快了不少。。几秒吧。。。原因应该是多case的mesmet head

    ③将2个for找B字符改成统计时存B字符位置。。也快了些。

    ④将加边的顺序改成先加左(上)边的边,再加右(下)边的边。。这个从17sec变成了3sec。。。

    ⑤将二分匹配的vis改成int,避免多次memset。。这个从3sec变成了100ms。。。

     

    第一点显然的剪枝,不说了。二三点好像快得也不是特别明显,不说了。

    第四点,假设某行某段是WBW,那先加左边,再加右边的结果是B->W2->W1,也就是优先右边。。。这样的话,

    如果某行某段是 BWBWBWBWBWBW,那匹配的时候,每个B都只需要匹配一个就成功,不需要回溯。。。。这个的前提是顺序匹配,即从1~2B

    反之,如果先加右边,再加左边的结果是B->W1->W2,也就是优先左边。。。那样的话就要回溯多次(因为还有列的影响)。。但如果是逆序匹配,即从2B~1,速度还是几秒

     

    第五点。。。应该是最有力的改进了。。。。传统的二分匹配的vis是bool,然后匹配前memset。。因为那些点一般是数百。。。

    但是我们可以把vis改成int,匹配的时候把if(vis[v])continue;改成if(vis[v]==ID)continue;

    二分图最大匹配当时学得不够深入啊╮(╯▽╰)╭。。。。今天学习了。。。。第四点是SF发现的。。。第五点是参考LC他们的。。。感谢SF陪我刷了一两页的AC...

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <iostream>
     4 #include <algorithm>
     5 #include <cmath>
     6 #include <string>
     7 #include <vector>
     8 #include <queue>
     9 #include <set>
    10 using namespace std;
    11 
    12 #define ll long long
    13 #define inf 0x3f3f3f3f
    14 #define eps 1e-8
    15 #define maxn 180000
    16 #define maxm 360000
    17 
    18 int vv[maxm],nxt[maxm];
    19 int head[maxn],E;
    20 void init(){memset(head,-1,sizeof(head));E=0;}
    21 void addedge(int u,int v){
    22     vv[E]=v,nxt[E]=head[u],head[u]=E++;
    23 }
    24 int pre[maxn];
    25 int vis[maxn];
    26 bool match(int x,int n,int ID){
    27     for(int i=head[x];i!=-1;i=nxt[i]){
    28         int v = vv[i]-n;
    29         if(vis[v]==ID)continue;
    30         vis[v] = ID;
    31         if(pre[v]==-1 || match(pre[v],n,ID)){
    32             pre[v]=x;
    33             return true;
    34         }
    35     }
    36     return false;
    37 }
    38 bool hungary(int n){
    39     memset(pre,-1,sizeof(pre));
    40     memset(vis,0,sizeof(vis));
    41     for(int i=1;i<=n;++i)
    42         if(match(i,n,i)==false)return false;
    43     return true;
    44 }
    45 
    46 char ch[555][555];
    47 int idx[555][555];
    48 int bx[maxn],by[maxn];
    49 int main(){
    50     int t;
    51     scanf("%d",&t);
    52     while(t--){
    53         int nn,mm;
    54         scanf("%d%d",&nn,&mm);
    55         memset(ch,0,sizeof(ch));
    56         for(int i=1;i<=nn;++i)scanf("%s",ch[i]+1);
    57         int B=0,W=0;
    58         for(int i=1;i<=nn;++i)for(int j=1;j<=mm;++j)
    59             if(ch[i][j]=='B')idx[i][j]=++B,bx[B]=i,by[B]=j;
    60             else if(ch[i][j]=='W')idx[i][j]=++W;
    61         if(B*2!=W){puts("NO");continue;}
    62         init();
    63         for(int b=1;b<=B;++b){
    64             int i=bx[b],j=by[b];
    65             if(ch[i-1][j]=='W')addedge(idx[i][j],B*2+idx[i-1][j]);
    66             if(ch[i+1][j]=='W')addedge(idx[i][j],B*2+idx[i+1][j]);
    67             if(ch[i][j-1]=='W')addedge(idx[i][j]+B,B*2+idx[i][j-1]);
    68             if(ch[i][j+1]=='W')addedge(idx[i][j]+B,B*2+idx[i][j+1]);
    69         }
    70         if(hungary(B<<1))puts("YES");
    71         else puts("NO");
    72     }
    73     return 0;
    74 }
    View Code
  • 相关阅读:
    Microsoft.NET User Group
    白话MVP 和 MVVM 【转】
    高效的二分法TOP MAX/TOP MIN分页存贮过程
    策略模式5
    说说我们项目组的例行会议
    合格的项目经理
    说说我们的招聘和面试
    web安全问题汇总
    ASP.NET中常用的优化性能方法
    说说我们安排的培训
  • 原文地址:https://www.cnblogs.com/nextbin/p/3706021.html
Copyright © 2020-2023  润新知