zoukankan      html  css  js  c++  java
  • [atARC119D]Grid Repainting 3

    将每一行和每一列分别作为一个点,当第$i$行第$j$列的格子为红色时,将第$i$行与第$j$列连边

    此时,考虑选择第$i$行的红色格子并将第$i$行的格子全部改成白色:

    关于这一操作的条件,即需要第$i$行有红色格子,从图中来看也即第$i$行对应的点度非0

    关于这一条件的影响,即第$i$行的红色格子都没了,从图中来看也即删去第$i$行对应的点所有出边

    根据上述分析,每一次操作即在图中选择一个度非0的点,并删除其所有出边,并且设最终选择了$x$个行对应的点和$y$个列对应的点,最大化$nm-(n-x)(m-y)$

    考虑其中的一个连通块(连通块之间显然是独立的),我们可以仅保留这个连通块中的任意一个点,并选择该连通块中其余的点

    具体来说,任取该连通块的一个生成树,并以需要保留的点为根,每一次不断选择一个叶子即可

    另一方面,显然无论如何我们都不可能删除一个连通块中的所有点,因此这已经最优了

    同时,我们仅关心每一个连通块中未选的点是行还是列,一个点的连通块显然不需要考虑,多个点的连通块必然同时含有行和列的点

    由此,求出所有连通块(不考虑一个点的连通块)的数量$k$以及$x-1$和$y-1$之和$X$和$Y$(其中$x$和$y$为该连通块中行和列对应的点数量),问题即求$f(x)=nm-(n-X-x)(m-Y-k+x)$在$xin [0,k]$的最大值,利用二次函数简单讨论即可

    方案根据上面的分析也不难构造,时间复杂度为$o(nm)$,可以通过

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 2505
     4 struct Edge{
     5     int nex,to;
     6 }edge[N*N*2];
     7 struct Op{
     8     int type,x,y;
     9 };
    10 vector<int>v[N<<1];
    11 vector<Op>ans;
    12 int E,n,m,x,y,scc,head[N<<1],vis[N<<1];
    13 char s[N][N];
    14 void add(int x,int y){
    15     edge[E].nex=head[x];
    16     edge[E].to=y;
    17     head[x]=E++;
    18 }
    19 void dfs(int k){
    20     if (vis[k])return;
    21     vis[k]=1;
    22     v[scc].push_back(k);
    23     for(int i=head[k];i!=-1;i=edge[i].nex)dfs(edge[i].to);
    24 }
    25 void dfs(int k,int fa){
    26     if (vis[k])return;
    27     vis[k]=1;
    28     for(int i=head[k];i!=-1;i=edge[i].nex)dfs(edge[i].to,k);
    29     if (fa>=0){
    30         if (k<n)ans.push_back(Op{0,k,fa-n});
    31         else ans.push_back(Op{1,fa,k-n});
    32     }
    33 }
    34 void write(){
    35     printf("%d
    ",ans.size());
    36     for(int i=0;i<ans.size();i++){
    37         ans[i].x++,ans[i].y++;
    38         if (ans[i].type==0)printf("X %d %d
    ",ans[i].x,ans[i].y);
    39         else printf("Y %d %d
    ",ans[i].x,ans[i].y);
    40     }
    41 }
    42 int main(){
    43     scanf("%d%d",&n,&m);
    44     memset(head,-1,sizeof(head));
    45     for(int i=0;i<n;i++){
    46         scanf("%s",s[i]);
    47         for(int j=0;j<m;j++)
    48             if (s[i][j]=='R'){
    49                 add(i,j+n);
    50                 add(j+n,i);
    51             }
    52     }
    53     for(int i=0;i<n+m;i++)
    54         if (!vis[i]){
    55             v[++scc].clear();
    56             dfs(i);
    57             if (v[scc].size()==1)scc--;
    58             else{
    59                 x--,y--;
    60                 for(int j=0;j<v[scc].size();j++){
    61                     if (v[scc][j]<n)x++;
    62                     else y++;
    63                 }
    64             }
    65         }
    66     memset(vis,0,sizeof(vis));
    67     if (m-n+x-y<0){
    68         for(int i=1;i<=scc;i++)
    69             for(int j=0;j<v[i].size();j++)
    70                 if (v[i][j]<n){
    71                     dfs(v[i][j],-1);
    72                     break;
    73                 }
    74         write();
    75     }
    76     else{
    77         for(int i=1;i<=scc;i++)
    78             for(int j=0;j<v[i].size();j++)
    79                 if (v[i][j]>=n){
    80                     dfs(v[i][j],-1);
    81                     break;
    82                 }
    83         write();
    84     }
    85 }
    View Code
  • 相关阅读:
    欢乐送小程序自动化探索实践
    看完这篇还不了解 Nginx,那我就哭了!
    测试人的技术栈
    Bug,项目过程中的重要数据
    什么是测试开发工程师?
    hdu 1219 AC Me
    hdu 1202 The calculation of GPA(算绩点问题)
    hdu1205吃糖果(插空法)
    hdu1201(18岁生日)
    hdu1231最大连续子序列
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14835572.html
Copyright © 2011-2022 走看看