zoukankan      html  css  js  c++  java
  • 2019牛客暑期多校训练营(第二场)

    传送门

    F.Partition priblem(DFS)

    •题意

      有 2n 个人,任意两个人之间都存在竞争值;

      定义 v[ i ][ j ] 表示 i 与 j 的竞争值为 v[ i ][ j ];

      将这 2n 个人划分成两组,每组有 n 人,组内的成员之间不存在竞争;

           竞争值为(i,j不同组)

    求竞争值最大是多少

    •思路

    先用sum记录总的竞争值

    再分别把k先后放入A,B两个组

    同组之间 减去竞争值

    直到2n个都分配完毕

    至于为什么是用总的做减法呢?

    是因为这样比较容易剪枝:

    当未分配的竞争值(也就是需要继续做减法的竞争值)<前面情况已得到的最大竞争值ans,这种情况可以不再讨论

    •代码

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 const int maxn=50;
     5 int t[maxn][maxn];
     6 int a[maxn],b[maxn];
     7 ll sum,ans;
     8 int n;
     9 void dfs(int curA,int curB,ll unt)//A B队员和未安排的关系
    10 {
    11     if(unt<ans) return ;
    12     if(curA>n||curB>n) return ;//每对4队人数限制为n
    13     int k=curA+curB+1;//下一个该安排的人的序号
    14     if(k>2*n)
    15     {
    16         ans=max(ans,unt);
    17         return ;
    18     }
    19     ll untA=unt,untB=unt;
    20 
    21     //归为A组
    22     a[curA]=k;
    23     for(int i=0;i<curA;i++)
    24         untA-=t[a[i]][k];
    25     dfs(curA+1,curB,untA);
    26 
    27     //k号归为B组
    28     b[curB]=k;
    29     for(int i=0;i<curB;i++)
    30         untB-=t[b[i]][k];
    31     dfs(curA,curB+1,untB);
    32 }
    33 
    34 
    35 int main()
    36 {
    37     cin>>n;
    38     for(int i=1;i<=2*n;i++)
    39     {
    40         for(int j=1;j<=2*n;j++)
    41         {
    42             cin>>t[i][j];
    43             if(j<i)
    44                 sum+=t[i][j];
    45         }
    46     }
    47     dfs(0,0,sum);
    48     cout<<ans<<endl;
    49 }
    View Code

    H.Second Large Rectangle(单调栈或悬线法)

    •题意

    给一个由01组成的NxM矩阵

    求全由1组成的第二大矩阵面积

    •思路1(单调栈)

    先预处理一下矩形的高,再利用单调栈求最大面积,根据最大面积求大面积

    设h[i][j]为第i行第j列的高(列连续的1)

    因为在利用单调栈求最大面积时,

    是通过每一行求最大面积

    所以可以优化二维h[i][j]变一维h[j]

    在更新矩形时,要注意矩形去重和大矩形内部的最大矩形

    •代码

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1005;
    stack<int> sta;
    char a[maxn][maxn];
    int h[maxn];//每一行每一列的高度
    int l[maxn],r[maxn];
    int n,m;
    struct node
    {
        int x1,y1;
        int x2,y2;
        int val;
    };
    struct node fir={0,0,0,0,0};
    struct node sec={0,0,0,0,0};
    
    void Broad()
    {
        while(!sta.empty())
            sta.pop();
    
        for(int i=1;i<=m;++i)
        {
            while(!sta.empty()&&h[sta.top()]>=h[i])
                sta.pop();
    
            l[i]=sta.empty()?1:sta.top()+1;
            sta.push(i);
        }
    
        while(!sta.empty())
            sta.pop();
    
        for(int i=m;i>=1;--i)
        {
            while(!sta.empty()&&h[sta.top()]>=h[i])
                sta.pop();
    
            r[i]=sta.empty()?m:sta.top()-1;
            sta.push(i);
        }
    }
    
    void update(node &n,int x1,int y1,int x2,int y2)
    {
        n.x1=x1;
        n.x2=x2;
        n.y1=y1;
        n.y2=y2;
        n.val=(x2-x1+1)*(y2-y1+1);
    }
    
    void Slove()
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                if(a[i][j]=='1') h[j]++;
                else h[j]=0;
            }
            Broad();
            for(int j=1;j<=m;j++)
            {
                //当前面积
                int curS=h[j]*(r[j]-l[j]+1);
                //当前坐标 (x1,y1)左上 (x2,y2)右下
                int x1=i-h[j]+1;
                int y1=l[j];
                int x2=i;
                int y2=r[j];
    
                if(curS>=fir.val)//当前面积>=最大面积时
                {
                    if(!(x1==fir.x1&&x2==fir.x2&&y1==fir.y1&&y2==fir.y2))//不是同一个矩形时
                    {
                        fir.val=curS;//更新最大矩形和第二大矩形
                        update(sec,fir.x1,fir.y1,fir.x2,fir.y2);
                        update(fir,x1,y1,x2,y2);
                    }
                }
                else if(curS>sec.val)//当前面积>第二大矩形时 更新
                    update(sec,x1,y1,x2,y2);
    
                int curxsub=(x2-x1)*(y2-y1+1);//(宽-1)*长
                int curysub=(y2-y1)*(x2-x1+1);//(长-1)*宽
                
                if(curxsub>sec.val)//当前矩形长-1的矩形面积>第二大矩形时 更新
                    update(sec,x1+1,y1,x2,y2);
    
                if(curysub>sec.val)//当前矩形宽-1的矩形面积>第二大矩形时 更新
                    update(sec,x1,y1+1,x2,y2);
            }
        }
    }
    
    int main()
    {
        cin>>n>>m;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                cin>>a[i][j];
    
        Slove();
        cout<<sec.val<<endl;
    }
    View Code

    •思路2(悬线法)

    悬线法裸题,(悬线法)

    利用悬线法处理出left[i][j],right[i][j]和up[i][j]

    更新矩阵与方法1相同

    坑点:

    在初始化时,只把为1的left[i][j],right[i][j],up[i][j]赋值,

    为0的不用赋值,如果赋值的话,也变成可以有面积的了

    (在这找了一个多小时bug,哭唧唧

    •代码

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1005;
    char a[maxn][maxn];
    int l[maxn][maxn],r[maxn][maxn],up[maxn][maxn];
    int n,m;
    struct node
    {
        int x1,y1;
        int x2,y2;
        int val;
    };
    struct node fir={0,0,0,0,0};
    struct node sec={0,0,0,0,0};
    void update(node &n,int x1,int y1,int x2,int y2)
    {
        n.x1=x1;
        n.x2=x2;
        n.y1=y1;
        n.y2=y2;
        n.val=(x2-x1+1)*(y2-y1+1);
    }
    
    void Slove()
    {
         for(int i=1;i<=n;i++)
            for(int j=2;j<=m;j++)//左边界 从左往右推
                if(a[i][j]=='1'&&a[i][j-1]=='1')
                    l[i][j]=l[i][j-1];
    
        for(int i=1;i<=n;i++)
            for(int j=m-1;j>=1;j--)//右边界 从右往左推
                if(a[i][j]=='1'&&a[i][j+1]=='1')
                    r[i][j]=r[i][j+1];
    
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                if(i>1&&a[i][j]=='1'&&a[i-1][j]=='1')
                {
                    up[i][j]=up[i-1][j]+1;
                    l[i][j]=max(l[i][j],l[i-1][j]);
                    r[i][j]=min(r[i][j],r[i-1][j]);
                }
                //下面跟方法一相同
                int curS=(r[i][j]-l[i][j]+1)*up[i][j];
                int x1=i-up[i][j]+1;
                int y1=l[i][j];
                int x2=i;
                int y2=r[i][j];
                if(curS>=fir.val)//当前面积>=最大面积时
                {
                    if(!(x1==fir.x1&&x2==fir.x2&&y1==fir.y1&&y2==fir.y2))//不是同一个矩形时
                    {
                        fir.val=curS;//更新最大矩形和第二大矩形
                        update(sec,fir.x1,fir.y1,fir.x2,fir.y2);
                        update(fir,x1,y1,x2,y2);
                    }
                }
                else if(curS>sec.val)//当前面积>第二大矩形时 更新
                    update(sec,x1,y1,x2,y2);
    ;
    
                int curxsub=(x2-x1)*(y2-y1+1);//(宽-1)*长
                int curysub=(y2-y1)*(x2-x1+1);//(长-1)*宽
    
                if(curxsub>sec.val)//当前矩形长-1的矩形面积>第二大矩形时 更新
                    update(sec,x1+1,y1,x2,y2);
    
                if(curysub>sec.val)//当前矩形宽-1的矩形面积>第二大矩形时 更新
                    update(sec,x1,y1+1,x2,y2);
    
            }
        }
    }
    
    int main()
    {
        cin>>n>>m;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                cin>>a[i][j];
                if(a[i][j]=='1')//只把为1的初始化!!!
                {
                    l[i][j]=j;
                    r[i][j]=j;
                    up[i][j]=1;
                }
            }
        }
        Slove();
        cout<<sec.val<<endl;
    }
    View Code
  • 相关阅读:
    [转]Oracle创建删除用户、角色、表空间、导入导出数据库命令行方式总结
    [转]23种设计模式与泡MM的关系
    [转]23种设计模式之间的关系
    [转]如何提高服务器的访问速度
    SVN所在的服务器IP改变了,肿么办
    HTML中ID与NAME的区别
    Java与.net异构平台上web service间复杂对象的互操作
    下一代OS系统展望之我见(针对windows,其他OS我不熟)
    使用axis开发java web service
    关于Java与DotNet异构平台WebService中enum对象的交互
  • 原文地址:https://www.cnblogs.com/MMMinoz/p/11221384.html
Copyright © 2011-2022 走看看