LNOI2018 splitting problem solution

Keywords: PHP

The main idea is to connect the opposite sides.
For this problem, the greedy strategy determines everyone's optimal solution in turn
But because there are many ways for each person to reach the optimal solution, if each tries, it will time out, so only one of them can be taken first
And connect this scheme with the opposite side and other schemes with the forward side.
In this way, for later decision-making, we can see which tutors can reach the meeting point.
It is to judge which tutor can be reached and which is better from BFS after reverse mapping.

For example: for this example

Build for

Consider player 1 first. Mentors 1 and 2 can reach the meeting point, and choosing mentors 1 and 2 is the best solution for the moment (it's impossible to determine which is better for later), so choose 1 first.

Graph changes to

(red is the opposite side)

Consider player 2. Mentors 1 and 2 can all reach the meeting point. 1 is better, so choose 1. Here we go to the opposite side and then to the 2 tutors, which is equivalent to letting the 1 contestant choose the 2 tutors.

This idea is similar to the augmented path algorithm of the maximum flow (both use the reverse edge to adjust the previous wrong decision).

This question has the sentence "the top i's admission result is the best, if and only if the top i − 1's admission result is the best: the top i's admission is the highest possible theory", which belongs to greed. In this way, we can use this idea.

#include <stdio.h>
int fr[410],ne[5010],lad[410];
int v[5010],w[5010],bs=0;
int dl[410],la[410],n,m,sy[210];
bool bk[410],xz[210][210];
int zy[210][210],jg[210],yq[210];
void addb(int a,int b,int c)
{
    v[bs]=b;
    w[bs]=c;
    ne[bs]=fr[a];
    fr[a]=bs;
    bs+=1;
}
void bfs()
{
    for(int i=1;i<=n+m;i++)
        bk[i]=false;
    int he=0,ta=0;
    for(int i=1;i<=m;i++)
    {
        if(sy[i]>0)
        {
            dl[ta]=i+n;
            la[i+n]=-1;
            bk[i+n]=true;
            ta+=1;
        }
    }
    while(he<ta)
    {
        for(int i=fr[dl[he]];i!=-1;i=ne[i])
        {
            if(w[i]>0&&!bk[v[i]])
            {
                bk[v[i]]=true;
                dl[ta]=v[i];
                la[v[i]]=i;
                lad[v[i]]=dl[he];
                ta+=1;
            }
        }
        he+=1;
    }
}
void jisuan()
{
    for(int i=1;i<=n;i++)
    {
        bfs();
        for(int j=1;j<=m;j++)
            xz[i][j]=bk[n+j];
        int t=-1;
        for(int j=1;j<=m;j++)
        {
            if((bk[n+j]&&zy[i][j]>0)&&(t==-1||zy[i][j]<zy[i][t]))
                t=j;
        }
        if(t==-1)
        {
            jg[i]=m+1;
            continue;
        }
        jg[i]=zy[i][t];
        int x=t+n;
        while(1)
        {
            if(la[x]==-1)
            {
                sy[x-n]-=1;
                break;
            }
            w[la[x]]-=1;
            w[la[x]^1]+=1;
            x=lad[x];
        }
        for(int j=1;j<=m;j++)
        {
            if(zy[i][j]==zy[i][t])
            {
                if(j==t)
                {
                    addb(i,j+n,1);
                    addb(j+n,i,0);
                }
                else
                {
                    addb(j+n,i,1);
                    addb(i,j+n,0);
                }
            }
        }
    }
}
int main()
{
    int T,C;
    scanf("%d%d",&T,&C);
    while(T--)
    {
        bs=0;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n+m;i++)
            fr[i]=-1;
        for(int i=1;i<=m;i++)
            scanf("%d",&sy[i]);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
                scanf("%d",&zy[i][j]);
        }
        for(int i=1;i<=n;i++)
            scanf("%d",&yq[i]);
        jisuan();
        for(int i=1;i<=n;i++)
            printf("%d ",jg[i]);
        printf("\n");
        for(int i=1;i<=n;i++)
        {
            int l=0,r=i;
            while(l<r)
            {
                int mi=(l+r)>>1;
                bool zd=false;
                for(int j=1;j<=m;j++)
                {
                    if(xz[i-mi][j]&&zy[i][j]!=0&&zy[i][j]<=yq[i])
                    {
                        zd=true;
                        break;
                    }
                }
                if(zd)
                    r=mi;
                else
                    l=mi+1;
            }
            printf("%d ",l);
        }
        printf("\n");
    }
    return 0;
}

Posted by CircularStopSign on Tue, 15 Oct 2019 10:15:49 -0700