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
原文地址:https://www.cnblogs.com/MMMinoz/p/11221384.html