zoukankan      html  css  js  c++  java
  • 搜索专题 题解

    一开始写在了word上……后来搬运了过来

    格式乱凑合看QAQ

    搜索专题 题解

    A.文化之旅

    题面有歧义的大水题,不谈。无限qj测试点

    B.寻找道路

    建反图跑dfs处理与终点连通性,最短路加特判水题不谈。

    C. 靶形数独

    预处理belong[]表示属于哪个九宫格,sc[]表示分数

    按行列搜会当场T飞,so每次遍历全图找到能填数最少的点进行搜索

    三个条件需同时满足可以二进制优化,然而我卡了过去。

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    using namespace std;
    int sc[12][12],vf[12][12],vh[12][12],vl[12][12],ans=-1,a[12][12],belong[12][12];
    int num0,nowx,nowy,score0;
    void pre()
    {
        int l=1,r=9;
        while(l<=r)
        {
            for(int i=l;i<=r;i++)
                sc[l][i]=sc[r][i]=sc[i][l]=sc[i][r]=l+5;
            l++;r--;
        }    
        belong[1][1]=1;
        belong[1][2]=1;
        belong[1][3]=1;
        belong[1][4]=2;
        belong[1][5]=2;
        belong[1][6]=2;
        belong[1][7]=3;
        belong[1][8]=3;
        belong[1][9]=3;
        belong[2][1]=1;
        belong[2][2]=1;
        belong[2][3]=1;
        belong[2][4]=2;
        belong[2][5]=2;
        belong[2][6]=2;
        belong[2][7]=3;
        belong[2][8]=3;
        belong[2][9]=3;
        belong[3][1]=1;
        belong[3][2]=1;
        belong[3][3]=1;
        belong[3][4]=2;
        belong[3][5]=2;
        belong[3][6]=2;
        belong[3][7]=3;
        belong[3][8]=3;
        belong[3][9]=3;
        belong[4][1]=4;
        belong[4][2]=4;
        belong[4][3]=4;
        belong[4][4]=5;
        belong[4][5]=5;
        belong[4][6]=5;
        belong[4][7]=6;
        belong[4][8]=6;
        belong[4][9]=6;
        belong[5][1]=4;
        belong[5][2]=4;
        belong[5][3]=4;
        belong[5][4]=5;
        belong[5][5]=5;
        belong[5][6]=5;
        belong[5][7]=6;
        belong[5][8]=6;
        belong[5][9]=6;
        belong[6][1]=4;
        belong[6][2]=4;
        belong[6][3]=4;
        belong[6][4]=5;
        belong[6][5]=5;
        belong[6][6]=5;
        belong[6][7]=6;
        belong[6][8]=6;
        belong[6][9]=6;
        belong[7][1]=7;
        belong[7][2]=7;
        belong[7][3]=7;
        belong[7][4]=8;
        belong[7][5]=8;
        belong[7][6]=8;
        belong[7][7]=9;
        belong[7][8]=9;
        belong[7][9]=9;
        belong[8][1]=7;
        belong[8][2]=7;
        belong[8][3]=7;
        belong[8][4]=8;
        belong[8][5]=8;
        belong[8][6]=8;
        belong[8][7]=9;
        belong[8][8]=9;
        belong[8][9]=9;
        belong[9][1]=7;
        belong[9][2]=7;
        belong[9][3]=7;
        belong[9][4]=8;
        belong[9][5]=8;
        belong[9][6]=8;
        belong[9][7]=9;
        belong[9][8]=9;
        belong[9][9]=9;
    }
    /*int belong(int hang,int lie)
    {
        if(hang>3)hang=(hang%3?hang/3:hang/3-1);
        else hang=0;
        if(lie>3)lie=(lie%3?lie/3:lie/3-1);
        else lie=0;
        return hang*3+lie+1;
    }*/
    int cacl()
    {
        int tot=0;
        for(int i=1;i<=9;i++)
            for(int j=1;j<=9;j++)tot+=a[i][j]*sc[i][j];
        return tot;
    }
    bool judge(int i,int j,int num)
    {
        if(vh[i][num]||vl[j][num]||vf[belong[i][j]][num])return 0;
        return 1;
    }
    void findloc()
    {
        nowx=nowy=0;
        int minx=0x3f3f3f3f;
        for(int i=1;i<=9;i++)
            for(int j=1;j<=9;j++)
            {
                if(a[i][j])continue;
                int res=0;
                for(int num=1;num<=9;num++)
                {
                    if(!judge(i,j,num))continue;
                    res++;
                }
                if(res<minx)minx=res,nowx=i,nowy=j;
            }    
    }
    void dfs(int hang,int lie)
    {    
        for(int num=1;num<=9;num++)
        {
            if(!judge(hang,lie,num))continue;
            vh[hang][num]=vl[lie][num]=vf[belong[hang][lie]][num]=1;
            a[hang][lie]=num;
            findloc();
            if(nowx==0||nowy==0)
                ans=max(ans,cacl());    
            else dfs(nowx,nowy);
            vh[hang][num]=vl[lie][num]=vf[belong[hang][lie]][num]=0;
            a[hang][lie]=0;
        }
        return ;
    }
    int main()
    {
        pre();
        for(int i=1;i<=9;i++)
            for(int j=1;j<=9;j++)
            {
                int x;
                scanf("%d",&x);
                a[i][j]=x;
                if(x)vh[i][x]=vl[j][x]=vf[belong[i][j]][x]=1,score0+=sc[i][j]*x;
            }
        findloc();
        dfs(nowx,nowy);
        cout<<ans<<endl;
        return 0;
    }
    View Code

     D.饮水入城

    首先跑bfs/dfs预处理每个湖城能引水到哪个沙城(事实证明后者效率会把前者虐出翔)  可以状压处理|在一起判出0的情况

    之后的东西就比较玄学(我赶脚是物理原理?)

    这里因为懒就直接粘miku的题解

    仔细看看题里给的图,我们可以发现如下定理

    ①:若在所以临湖城市都建蓄水站,如果没能覆盖所有沙漠城市,则剩下的城市就是不能覆盖的城市

    ②:若能完成覆盖,则每个点一定能覆盖一段城市

     

    ③:一个点能覆盖的最左城市不可能超过它左边的点能覆盖的最左城市(一个城市也不能覆盖的点除外)

     

    这个性质发现之后整道题迎刃而解

    %%%mikufunTQL

    之后转化成了区间最小覆盖问题 记录左右端点dp解决

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<queue>
    #include<bitset>
    using namespace std;
    const int N=510;
    const int dx[5]={0,1,0,-1,0},
              dy[5]={0,0,1,0,-1};
    bitset<501> v[N];          
    int n,m;
    int h[N][N],s[N][N],f[N];
    struct seg
    {
        int l,r;
        friend bool operator < (seg a1,seg a2)
        {
            return a1.l==a1.r?a1.r<a2.r:a1.l<a2.l;
        }
    }a[N];
    queue<int> x,y;
    int read()
    {
        int xx=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9')
            {if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')
            {xx=xx*10+ch-'0';ch=getchar();}
        return xx*f;
    }
    void bfs(int xs,int ys)
    {
        memset(s,0,sizeof(s));
        x.push(xs);y.push(ys);
        while(!x.empty())
        {
            for(int i=1;i<=4;i++)
            {
                int nowx=x.front(),nxtx=nowx+dx[i],nowy=y.front(),nxty=nowy+dy[i];
                if(h[nxtx][nxty]>=h[nowx][nowy]||s[nxtx][nxty]||nxtx==0||nxty==0||nxtx>n||nxty>m)continue;
                s[nxtx][nxty]=1;
                x.push(nxtx);y.push(nxty);
            }
            x.pop();y.pop();
        }
        for(int i=1;i<=m;i++)
            if(s[n][i])v[ys][i]=1;
    }
    int main()
    {
        n=read();m=read();
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)h[i][j]=read();
        for(int i=1;i<=m;i++)bfs(1,i);
        bitset<501> all;all=v[1];int cnt0=0;
        for(int i=2;i<=m;i++)all|=v[i];
        for(int i=1;i<=m;i++)
        {
            if(!all[i])cnt0++;
            for(int j=1;j<=m;j++)
                if(v[i][j])
                {
                    a[i].l=j;
                    while(v[i][j])j++;
                    a[i].r=j-1;
                    break;
                }
        }    
        if(cnt0)
        {
            if(n==1)puts("1");
            else puts("0");
            cout<<cnt0<<endl;
            return 0;
        }
        puts("1");
        memset(f,0x3f,sizeof(f));
        f[0]=0;
        for(int i=1;i<=m;i++)
            for(int j=1;j<=m;j++)
                if(a[j].l<=i&&a[j].r>=i)
                f[i]=min(f[i],f[a[j].l-1]+1);
        cout<<f[m]<<endl;
        return 0;
    } 
    View Code

     E.传染病控制

    水题,只要不想成树dp一切好说

    (然后我就不好说了)

    从上往下每层砍条边,使留下的节点最少

    预处理一下直接按深度暴搜(打标记/取消)

    建图的时候父子关系不明是坑点Orz

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<vector>
    using namespace std;
    const int N=310;
    int to[N<<1],nxt[N<<1],head[N],tot=0,d[N<<1];
    int n,m,ans=0x3f3f3f3f;
    int size[N],cut[N];
    vector<int> dep[N];
    void add(int x,int y)
    {
        to[++tot]=y;
        nxt[tot]=head[x];
        head[x]=tot;
    }
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9')
            {if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')
            {x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    int predfs(int x,int deep)
    {
        d[x]=deep;dep[deep].push_back(x);
        for(int i=head[x];i;i=nxt[i])
            size[x]+=predfs(to[i],deep+1);
        return size[x];
    }
    void cutson(int x)
    {
        cut[x]=1;
        for(int i=head[x];i;i=nxt[i])
            cutson(to[i]);
    }
    void recover(int x)
    {
        cut[x]=0;
        for(int i=head[x];i;i=nxt[i])
            recover(to[i]);
    }
    void dfs(int deep,int now)
    {
        for(int i=0;i<dep[deep+1].size();i++)
        {
            int y=dep[deep+1][i];
            if(cut[y])continue;
            cutson(y);
            dfs(deep+1,now-size[y]);
            recover(y);
        }
        ans=min(ans,now);
    }
    int main()
    {
        n=read();m=read();
        for(int i=1;i<=n;i++)size[i]=1;
        for(int i=1;i<=m;i++)
        {
            int x=read(),y=read();
            if(x>y)swap(x,y);
            add(x,y);
        }
        predfs(1,1);
        dfs(1,n);
        cout<<ans<<endl;
        return 0;
    }
    View Code

     F.虫食算

    这道题思考比较充分,打的时候思路也比较清晰

    (然而还是没有1A  水到T90)

    加一个随时检查当前填数情况是否完全合法的函数来剪枝

    然后按列往前搜就完事了

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    using namespace std;
    int n,num[31],rev[31];
    char a[5][31];
    int mod(int x)
    {
        return x>=n?x-n:x;
    }
    int t(char x)
    {
        return (int)(x-'A');
    }
    void print()
    {
        for(int i=0;i<n;i++)printf("%d ",num[i]);
    }
    void ini()
    {
        for(int i=0;i<=n;i++)num[i]=rev[i]=-1;
    }
    bool judge()
    {
        for(int i=n;i>=1;i--)
        {
            if(num[t(a[1][i])]==-1||num[t(a[2][i])]==-1||num[t(a[3][i])]==-1)continue;
            int a1=num[t(a[1][i])],a2=num[t(a[2][i])],sum=num[t(a[3][i])];
            if(mod(a1+a2)!=sum&&mod(a1+a2+1)!=sum)return 0;
        }
        return 1;
    }
    bool dfs(int now,int line,int jw)
    {    
        /*cout<<endl<<now<<' '<<line<<endl;
        for(int i=0;i<n;i++)cout<<num[i]<<' ';
        cout<<endl;*/
        if(line==3)
        {
            int sum=mod(num[t(a[1][now])]+num[t(a[2][now])]+jw);
            if(num[t(a[1][now])]+num[t(a[2][now])]+jw>=n)jw=1;
            else jw=0;
            if(num[t(a[3][now])]==-1)
            {
                if(rev[sum]!=-1)return 0;
                num[t(a[3][now])]=sum;
                rev[sum]=num[t(a[3][now])];
                if(now==1)
                {
                    print();
                    return 1;
                }
                else if(judge())dfs(now-1,1,jw);
                num[t(a[3][now])]=rev[sum]=-1;
            }
            else if(num[t(a[3][now])]==sum)
            {
                if(now==1)
                {
                    print();
                    return 1;
                }
                else dfs(now-1,1,jw);
            }
            else return 0;
        }
        else
        {
            if(num[t(a[line][now])]!=-1&&judge)dfs(now,line+1,jw);
            else for(int i=0;i<n;i++)
            {
                if(rev[i]!=-1)continue;
                num[t(a[line][now])]=i;
                rev[i]=num[t(a[line][now])];
                if(judge()==0)
                {
                    num[t(a[line][now])]=rev[i]=-1;
                    continue;
                }
                dfs(now,line+1,jw);
                num[t(a[line][now])]=rev[i]=-1;
            }
        }
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=3;i++)scanf("%s",a[i]+1);
        ini();
        dfs(n,1,0);
        return 0;
    }
    View Code

     G.斗地主

    其实还是蛮水的

    主要是坑点多,规则繁杂

    什么2不能当顺子 对王可以带之类的

    鄙蒟蒻没有预处理散牌 而是先出顺子等丢牌较快的操作 最后考虑散牌  由于单对三炸都能一下出完直接if(sum[i])num++就完事了

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<vector>
    #include<algorithm>
    using namespace std;
    int c[25];
    int T,n,ans=0x3f3f3f3f;
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9')
            {if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')
            {x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    void dfs(int num)
    {
        if(num>=ans)return ;
        
        int now=0;
        for(int i=3;i<=14;i++)
        {
            if(!c[i])now=0;
            else 
            {
                now++;
                if(now>=5)
                {
                    for(int j=i;j>=i-now+1;j--)c[j]--;
                    dfs(num+1);
                    for(int j=i;j>=i-now+1;j--)c[j]++;
                }
            }
        }
        now=0;//cout<<"****"<<endl;
        for(int i=3;i<=14;i++)
        {
            if(c[i]<2)now=0;
            else
            {
                now++;
                if(now>=3)
                {
                    for(int j=i;j>=i-now+1;j--)c[j]-=2;
                    dfs(num+1);
                    for(int j=i;j>=i-now+1;j--)c[j]+=2;
                }
            }
        }
        now=0;
        for(int i=3;i<=14;i++)
        {
            if(c[i]<3)now=0;
            else
            {
                now++;
                if(now>=2)
                {
                    for(int j=i;j>=i-now+1;j--)c[j]-=3;
                    dfs(num+1);
                    for(int j=i;j>=i-now+1;j--)c[j]+=3;
                }
            }
        }
        for(int i=2;i<=14;i++)
        {
            if(c[i]<=2)continue;
            if(c[i]==3)
            {
                c[i]-=3;
                for(int j=2;j<=15;j++)
                {
                    if(c[j]==0||i==j)continue;
                    c[j]--;
                    dfs(num+1);
                    c[j]++;
                }
                for(int j=2;j<=14;j++)
                {
                    if(c[j]<2||i==j)continue;
                    c[j]-=2;
                    dfs(num+1);
                    c[j]+=2;
                }
                c[i]+=3;
            }
            else if(c[i]>3)
            {
                c[i]-=3;
                for(int j=2;j<=15;j++)
                {
                    if(c[j]==0||i==j)continue;
                    c[j]--;
                    dfs(num+1);
                    c[j]++;
                }
                for(int j=2;j<=14;j++)
                {
                    if(c[j]<2||i==j)continue;
                    c[j]-=2;
                    dfs(num+1);
                    c[j]+=2;
                }
                c[i]+=3;
                
                c[i]-=4;
                for(int j=2;j<=15;j++)
                {
                    if(c[j]==0||i==j)continue;
                    c[j]--;
                    for(int k=2;k<=15;k++)
                    {
                        if(c[k]==0||i==k||k==j)continue;
                        c[k]--;
                        dfs(num+1);
                        c[k]++;
                    }
                    c[j]++;
                }
                for(int j=2;j<=14;j++)
                {
                    if(c[j]<2||i==j)continue;
                    c[j]-=2;
                    for(int k=2;k<=14;k++)
                    {
                        if(c[k]<2||i==k||k==j)continue;
                        c[k]-=2;
                        dfs(num+1);
                        c[k]+=2;
                    }
                    c[j]+=2;
                }
                c[i]+=4;                        
            }
        }
        for(int i=2;i<=15;i++)
            if(c[i])num++;
        ans=min(ans,num);
    }
    void work()
    {
        memset(c,0,sizeof(c));
        ans=0x3f3f3f3f;
        for(int i=1;i<=n;i++)
        {
            int x=read(),tmp=read();
            if(!x)c[15]++;
            else if(x==1)c[14]++;
            else c[x]++;
        }
        dfs(0);
        printf("%d
    ",ans);
    }
    int main()
    {
        T=read();n=read();
        while(T--)work();
        return 0;
    }
    View Code

    H.Mayan游戏

    美妙大模拟

    多写函数、码风清晰能省去不少调试的时间

    剪枝:

    相同颜色块直接跳过(Obviously)

    固定方向移动:右边有块or左边没块  省去重复判断

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    using namespace std;
    #define rint register int
    int n,ans[10][5],map[10][10],st[10][10][10];
    bool no[10][10];
    inline int Read()
    {
        register int ret;
        register char r;
        while(r=getchar(),r<'0'||r>'9');ret=r-48;
        while(r=getchar(),r>='0'&&r<='9')ret=ret*10+r-48;
        return ret;
    }
    void save(int now)
    {
        for(int i=1;i<=5;i++)
            for(int j=1;j<=7;j++)
                st[now][i][j]=map[i][j];
    }
    void recover(int now)
    {
        for(int i=1;i<=5;i++)
            for(int j=1;j<=7;j++)
                map[i][j]=st[now][i][j];
    }
    void drop()
    {
        for(rint i=1;i<=5;i++)
        {
            int x=0;
            for(rint j=1;j<=7;j++)
            {
                if(!map[i][j])x++;
                else
                {
                    if(!x)continue;
                    map[i][j-x]=map[i][j];
                    map[i][j]=0;
                }
            }
        }
    }
    bool boom()
    {
        rint ok=0;
        for(rint i=1;i<=5;i++)
            for(rint j=1;j<=7;j++)
            {
                if(i>=2&&i<=4&&map[i][j]==map[i-1][j]&&map[i][j]==map[i+1][j]&&map[i][j])
                    no[i-1][j]=no[i+1][j]=no[i][j]=ok=1;
                if(j>=2&&j<=6&&map[i][j]==map[i][j-1]&&map[i][j]==map[i][j+1]&&map[i][j])
                    no[i][j-1]=no[i][j+1]=no[i][j]=ok=1;
            }
        if(!ok)return 0;
        for(rint i=1;i<=5;i++)
            for(rint j=1;j<=7;j++)
                if(no[i][j])no[i][j]=map[i][j]=0;
        return 1;                
    }
    bool finish()
    {
        for(rint i=1;i<=5;i++)
            if(map[i][1])return 0;
        return 1;
    }
    void move(int i,int j,int x)
    {
        swap(map[i][j],map[i+x][j]);
        drop();
        while(boom())drop();
    }
    void dfs(int x)
    {
        if(finish())
        {
            for(rint i=1;i<=n;i++)
            {
                for(rint j=1;j<=3;j++)printf("%d ",ans[i][j]);
                puts(" ");
            }
            exit(0);
        }
        if(x>n)return ;
        save(x);
        for(rint i=1;i<=5;i++)
            for(rint j=1;j<=7;j++)
            {
                if(map[i][j])
                {
                    if(i<=4&&map[i][j]!=map[i+1][j])
                    {
                        move(i,j,1);
                        ans[x][1]=i-1;ans[x][2]=j-1;ans[x][3]=1;
                        dfs(x+1);
                        recover(x);
                        ans[x][1]=ans[x][2]=ans[x][3]=-1;
                    }
                    if(i>=2&&!map[i-1][j])
                    {
                        move(i,j,-1);
                        ans[x][1]=i-1;ans[x][2]=j-1;ans[x][3]=-1;
                        dfs(x+1);
                        recover(x);
                        ans[x][1]=ans[x][2]=ans[x][3]=-1;
                    }
                }
            }
    }
    
    int main()
    {
        n=Read();
        for(rint i=1;i<=5;i++)
            for(rint j=1;j<=8;j++)
            {
                int x;
                x=Read();
                if(!x)break;
                map[i][j]=x;
            }
        memset(ans,0xFF,sizeof(ans));dfs(1);
        puts("-1");
        return 0;
    }
    View Code
  • 相关阅读:
    C# 根据主窗体的位置弹窗信息窗体一直保持在主窗体中间
    c# winForm父子窗口 通过委托进行信息传递
    使用devexpress插件 消除运行时弹窗
    C# 获取当前时间戳
    WinForm实现Loading等待界面
    转载 C#设置控件 Enabled 为 false 时背景色不改变
    DEV gridView中加入加载条显示进度,必须为圆角型
    winfrom 圆角化
    列表元素的反转、排序——python
    使用for循环和while循环打印九九乘法表——python
  • 原文地址:https://www.cnblogs.com/Rorschach-XR/p/11009058.html
Copyright © 2011-2022 走看看