DFS-深度优先搜索(深搜)

先摘一段官话:深度优先搜索(Depth First Search)是搜索的手段之一。它是从某个状态开始,不断的转移状态直到无法转移,然后退回到前一步的状态,继续转移到其他的状态,如此不断的重复,直至找到最终的解。

其大致的过程如下:
 (1)访问搜索到的未被访问的邻接点;
 (2)将此顶点标记为已访问节点;
 (3)搜索该顶点的未被访问的邻接点,若该邻接点存在,则从此
邻接点开始进行同样的访问和搜索。

说到这个深搜,我就想起了我多年前玩的一个游戏,页游!wap页游!纯文字!叫大话水浒,现在还在运营,游戏里有一个地下迷宫,目标是找出口打怪开宝箱。现在想起来当时我玩这个游戏的思路就和深搜的解题思路一mao一样。游戏还原链接(https://www.windfamily.cn/module/games/maze.html)。深搜的解题思路就好像走那个迷宫,一开始找到一个可以走的方向,不停的往这个方向走,路上看到了其它路口,记在心里,告诉自己不要慌,如果一个方向走不通,还可以回来走这个方向。当那个方向被围住或者走不通时,就往回走,直到碰到最近的之前遇到过的路口,然后一样的往这个方向走,重复上面的步骤。深搜具体实现时和它的区别就是当一个方向走到头时你不用往回走,因为你走过的地方都被标记过,不能走了,系统(递归回溯)会帮你自动跳回到你之前遇到过的最近的路口。

1. 先看一道例题:白与黑:http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=784

#include <bits/stdc++.h>

using namespace std;

int w,h;
int num;
string a[101];
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};        //搜索的方向

int dfs(int x,int y)
{
    a[x][y]='#';            //走过的路都给它标记上
    for(int i=0;i<4;i++)    //这个for循环就是在某点上看看四个方向能不能走
    {
        int newx=x+dir[i][0];
        int newy=y+dir[i][1];
        if(newx>=0 && newx<h && newy>=0 && newy<w && a[newx][newy]!='#')
        {
            num++;
            dfs(newx,newy);            //其实递归有储存发现的路口的意味
        }
    }
}

int main()
{
    int i,j;
    while(scanf("%d%d",&w,&h)!=-1)
    {
        if(w==0 && h==0) break;
        num=1;
        for(i=0;i<h;i++) cin>>a[i];   //必须用cin,string用cin才能被正确处理
        for(i=0;i<h;i++)
        {
            for(j=0;j<w;j++)
            if(a[i][j]=='@')
            {
                dfs(i,j);
                break;
            }
        }
        printf("%d\n",num);
    }
}

说明一下,生成newx,newy后,如果符合if条件进入if就说明这一步可以走,而当dfs(newx,newy)的时候就说明这一步现在已经走了(因为它马上要被标记为'#'),现在要考虑这步走完的下一步。 

2. 搜索入门:http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=912

#include <bits/stdc++.h>

using namespace std;
string a[5];
int flag;
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
int dfs(int x,int y)
{
    a[x][y]='*';
    for(int i=0;i<4;i++)
    {
        int newx=x+dir[i][0];
        int newy=y+dir[i][1];
        if(newx>=0 && newx<4 && newy>=0 && newy<4 && a[newx][newy]=='#')
        {
            if(newx==3 && newy==3)
            {
                 flag=1;
                 break;
            }
            else dfs(newx,newy);
            
        }
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        flag=0;
        for(int i=0;i<4;i++) cin>>a[i];
        dfs(0,0);
        if(flag==0) printf("NO\n");
        else printf("YES\n");
    }
}

上一题懂了这题自然没问题。

3. 迷宫寻路:http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=558

从这题中得到一个惨痛的教训:i一定不能是全局的(因为其它地方也用到i所以小心啊),否则递归迭代的时候i会累加。

同时提供除了利用flag判断能否到达终点的另一种方法。

#include <bits/stdc++.h>

using namespace std;

int n,m;
int stx,sty,enx,eny;
string a[1005];
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};

void dfs(int x,int y)
{
    a[x][y]='#';
    for(int i=0;i<4;i++)        //啊啊啊,这里的i一定不能设成全局的,否则递归的时候会完蛋
    {
        int newx=x+dir[i][0];
        int newy=y+dir[i][1];
        if(newx>=0 && newx<n && newy>=0 && newy<m && a[newx][newy]=='*')
        {
            dfs(newx,newy);
        }
    }
}
int main()
{
    while(scanf("%d%d",&n,&m)!=-1)
    {
        stx=sty=enx=eny=-1;
        for(int i=0;i<n;i++) cin>>a[i];

        for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
        {
            if((i==0 || i==n-1 || j==0 || j==m-1) && a[i][j]=='*')
            {
                if(stx==-1) stx=i,sty=j;
                else enx=i,eny=j;
            }
        }
        dfs(stx,sty);
        if(a[enx][eny]!='#') printf("NO\n");
        else printf("YES\n");
    }
}

4. 最大黑色区域:http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=1694

这道题一开始看上去没啥思路,其实很简单,就是一个大矩阵可以分成很多各小矩阵来搜(因为各区域面积被0隔离),只要遍历矩阵,看到1就开始搜,得到该部分面积(1个数)的最大值,然后进行比较即可。

然后这道题一开始踩了一个坑,就是maxs只能初始化为0,因为样例中可能存在全为0的情况。

#include <bits/stdc++.h>

using namespace std;

int n,m;
int maxs,nows;
int a[1005][1005];
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
int dfs(int x,int y)
{
    nows++;
    a[x][y]=0;
    for(int i=0;i<4;i++)
    {
        int newx=x+dir[i][0];
        int newy=y+dir[i][1];
        if(newx>=0 && newx<n && newy>=0 && newy<m && a[newx][newy]==1)
        {
            dfs(newx,newy);
        }
    }

}
int main()
{
    scanf("%d%d",&n,&m);
    maxs=0;        //这里
    for(int i=0;i<n;i++)
    for(int j=0;j<m;j++)
    scanf("%d",&a[i][j]);

    for(int i=0;i<n;i++)
    for(int j=0;j<m;j++)
    if(a[i][j]==1)
    {
        nows=0;
        dfs(i,j);
        maxs=max(maxs,nows);
    }
       
    printf("%d\n",maxs);
}

5. 猴群:http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=1696

这道题与第四题极为相似,除了一些细节方面,思路和第四题一样。

#include <bits/stdc++.h>

using namespace std;
int n,m;
int num;
string a[105];
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
int dfs(int x,int y)
{
    a[x][y]='0';
    for(int i=0;i<n;i++)
    {
        int newx=x+dir[i][0];
        int newy=y+dir[i][1];
        if(newx>=0 && newx<n && newy>=0 && newy<m && a[newx][newy]!='0')
        {
            dfs(newx,newy);
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    num=0;
    for(int i=0;i<n;i++) cin>>a[i];
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            if(a[i][j]!='0')
            {
                num++;
                dfs(i,j);
            }
        }
    }
    printf("%d\n",num);
}

6. 面积:http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=1699

这道题思路就是从为0的边缘开始搜,把搜到的0变为1,最后统计剩余0的个数即可。

#include <bits/stdc++.h>

using namespace std;
int num;
int a[15][15];
const int n=10;
int dir[4][2]={{-1,0},{1,0},{0,1},{0,-1}};
int dfs(int x,int y)
{
    a[x][y]=1;
    for(int i=0;i<4;i++)
    {
        int newx=x+dir[i][0];
        int newy=y+dir[i][1];
        if(newx>=0 && newx<n && newy>=0 && newy<n && a[newx][newy]==0)
        {
            dfs(newx,newy);
        }
    }
}

int main()
{
    for(int i=0;i<n;i++)
    for(int j=0;j<n;j++)
    scanf("%d",&a[i][j]);

    for(int i=0;i<n;i++)
    for(int j=0;j<n;j++)
    if((i==0 || i==n-1 || j==0 || j==n-1) && a[i][j]==0)
    dfs(i,j);

    num=0;
    for(int i=0;i<n;i++)
    for(int j=0;j<n;j++)
    if(a[i][j]==0) num++;

    printf("%d\n",num);
}

7.  数的划分:http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=1776

将整数 n 分成 k 份,且每份不能为空,问有多少种不同的分法。
当 n=7, k=3 时,下面三种分法被认为是相同的:1,1,5; 1,5,1; 5,1,1

Input
一行两个数 n, k

Output
一行一个整数,即不同的分法数。

为什么说这道题也能搜索呢?请看下图:

例子中数据n=7,k=3,答案是4。

对于一个数,我们可以第一次可以将它从划分为1~n的数,图中给出了第一次划分为1的情况,对于划分为1的情况,因为题目中说数字相同而顺序不同的组合看成一种,那么我们可以假设后划分的数大于等于先划分的数,于是第二次就可以从1~n-1再次划分,第三次可以从1~n-2划分。

如果对于每一层都进行这样的划分,那么就可以形成一棵庞大的树,我们要做的就是用深搜从不停遍历一个分支到底,看这个分支上数的和等不等于n,然后回退到上一层。是不是还是和之前的走迷宫思路一样?

代码:递归实现

#include <bits/stdc++.h>

using namespace std;

int n,k;
int num=0;

int dfs(int nown,int sum,int nowk)  //nown表示当分支的节点上的数,sum表示分支上的和,nowk表示进行到第几层
{
    if(nowk==k)        //如果遍历完k层,就判断它的和是否为n,是就说明找到一种情况。
    {
        if(sum==n) num++;
        return 0;
    }
    for(int i=nown;sum+i*(k-nowk)<=n;i++)        //生成树(利用递归一次只生成一个分支)
    {
        dfs(i,sum+i,nowk+1);
    }
}

int main()
{
    scanf("%d%d",&n,&k);
    dfs(1,0,0);            //从1开始划分
    printf("%d\n",num);
}

8. 01迷宫:http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=1702

这道题的解题思路:就是看看有多少个连通的区域,然后看看每一点属于哪个连通区域。要明确在起点在0时能走到的连通区域内,若以1为起点,也能走遍这个区域。判断相邻两点之间能不能走,可以用异或判断,只有异或值为1才可以走。

#include <bits/stdc++.h>

using namespace std;

int n,m;
int connectnum;       //连通区域个数
string a[1005];
int connectarea[1000005];    //某连通区域能移动的格子数
int wcb[1005][1005];  //which connectarea belong某点属于哪一个连通区域
int dir[4][2]={{-1,0},{1,0},{0,1},{0,-1}};

int dfs(int x,int y)
{
    wcb[x][y]=connectnum;   //确定格子属于哪个连通区域
    connectarea[connectnum]++;  //当前连通区域格子数加1
    int t=a[x][y]-'0';
    for(int i=0;i<4;i++)
    {
        int newx=x+dir[i][0];
        int newy=y+dir[i][1];
        if(newx>=0 && newx<n && newy>=0 && newy<n && wcb[newx][newy]==0 && ((a[newx][newy]-'0')^t)==1)
        {
            dfs(newx,newy);
        }
    }
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++) cin>>a[i];
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(wcb[i][j]==0)
            {
                connectnum++;
                dfs(i,j);
            }
        }
    }
    for(int i=0;i<m;i++)
    {
        int in,jn;
        scanf("%d%d",&in,&jn);
        int belong=wcb[in-1][jn-1];
        printf("%d\n",connectarea[belong]);
    }
}

9. 奇怪的电梯:http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=1697

与之前不同的是,这题方向是一维的,只能上下移动,确定起点后,搜就是了,看能不能到终点,能就和最短距离比取小。

需要注意的是,这题同样需要标记走过的地方,否则会死循环,走到哪里就把那里标记为不能走的,不要担心你担心可能出现的情况,因为这轮的标记只对这轮有效,递归回退的时候会把标记恢复为没走过,从而进行让下一分支继续走。

这题绊了我好久,思路是对的,递归的方法用错了,当前位置和按电梯的次数是要放在进行递归的,否则次数没办法回退。又得到一个宝贵的经验。还有就是要注意剪枝,否则直接TLE。

先看正确代码:

#include <bits/stdc++.h>

using namespace std;

int n,a,b;
int minn=9999999;
int lift[205],vis[205];
int dir[2]={1,-1};

int dfs(int now,int pressnum)
{
    if(now==b)
    {
        minn=min(minn,pressnum);
        return 0;
    }
    if(pressnum<minn)        //!import,否则TLE
    for(int i=0;i<2;i++)
    {
        int newnow=now+dir[i]*lift[now];
        if(newnow>=1 && newnow<=n && vis[newnow]==0)
        {
            vis[newnow]=1;
            dfs(newnow,pressnum+1);    //这里的千万不能用++,否则会影响同级分支,失去回退效果
            vis[newnow]=0;             //之前说的标记回退
        }
    }
}

int main()
{
    scanf("%d%d%d",&n,&a,&b);
    for(int i=1;i<=n;i++) scanf("%d",&lift[i]);
    memset(vis,0,sizeof(vis));
    vis[a]=1;
    if(a==b)                //这个if其实可以不要
    {
        printf("0\n");
        return 0;
    }
    dfs(a,0);
    if(minn==9999999) printf("%d\n",-1);
    else printf("%d\n",minn);
}

然后看我之前写的错误代码:

#include <bits/stdc++.h>
using namespace std;
int n,a,b;
int num,minnum=99999999;
int lift[2005];
int vis[2005];

int dir[3]={1,-1};

int dfs(int from)
{
    if(num<minnum)            //这个地方必须进行剪枝,否则超时,但这么做else情况num无法回退
    for(int i=0;i<2;i++)
    {
        int to=from+dir[i]*lift[from];
        if(to>=1 && to<=n && vis[to]==0)
        {
            num++;
            vis[to]=1;
            if(to==b)
            {
                minnum=min(minnum,num);
                return 0;
            }
            dfs(to);
            num--;
            vis[to]=0;
        }
    }
}

int main()
{
    scanf("%d%d%d",&n,&a,&b);
    for(int i=1;i<=n;i++) scanf("%d",&lift[i]);
    num=0;
    if(a==b)            //这种情况下必须写
    {
         printf("0\n");
         return 0;
    }
    vis[a]=1;
    dfs(a);
    if(minnum>=99999999) printf("-1\n");
    else printf("%d\n",minnum);
}

就是这样了,如果有大神知道这种情况下的修改方案,还请赐教。

10. 艾拉的选举:http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=1672

这题应该算是压轴题了,有些复杂。

首先从第一个评委对第一个选手评分开始搜索,然后继续进行第一个评委对后续评委的评分,当第一个评委评完分后换下一个评委继续评分搜索,当所有评委都评完分后,进行排序,num[order][名次]++;整棵树应该是这样的(只画出部分):

                                            

看代码: 

#include <bits/stdc++.h>

using namespace std;
struct student{    //用结构体储存那啥的序号,以及当前拥有的分数(开始是初始分数)
    int order;
    int mark;
}a[5];

int n,m;
int b[5];          //储存评委能打的分数
int vis[5][5];     //用于第x个评委是否用过第i个分数
int num[5][5];     //储存第i个那啥获得第j名的次数

bool cmp(student a,student b)        //当所有评委对所有那啥评完分进行排序时的比较函数
{
    if(a.mark!=b.mark) return a.mark>b.mark;
    else return a.order<b.order;
}

int dfs(int x,int y)
{
    if(y==n+1)        //当一个评委对所有选手评完分后,换下一个评委
    {
        dfs(x+1,1);
        return 0;
    }
    if(x==m+1)        //当所有评委对所有选手评完分后对分数进行排序
    {
        student t[5];    //用临时数组进行排序,否则递归回退的时候会减错位置
        for(int i=1;i<=n;i++) t[i]=a[i];
        sort(t+1,t+n+1,cmp);
        for(int j=1;j<=n;j++)  num[t[j].order][j]++;
        return 0;
    }
    for(int i=1;i<=n;i++)    //评委对第1位到n位选手评分
    {
        if(vis[x][i]==0)    //确定该评委没用过某一分数
        {
            vis[x][i]=1;
            a[y].mark=a[y].mark+b[i];
            dfs(x,y+1);
            vis[x][i]=0;      //递归回退
            a[y].mark-=b[i];   //要用临时数组排序的原因
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
         a[i].order=i;
         scanf("%d",&a[i].mark);
    }
    for(int i=1;i<=n;i++) scanf("%d",&b[i]);
    dfs(1,1);            //搜索起点:第1个评委对1个选手评分
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        if(j==n) printf("%d\n",num[i][j]);
        else printf("%d ",num[i][j]);
    }
}

这原本是寒假集训时一场考试的题,那时候还没学到搜索,某个变态老学长出的题(手动滑稽),出题解的时候他告诉我们可以暴力循化做,于是就有了以下惊为天人的代码(吐血):

#include<bits/stdc++.h>
using namespace std;
long long b1[30][6];
long long a[6];
long long b[6];
long long x,y,z,q;
long long js[6][6];
struct sz{
long long zhi;
int wz;
}cz[6];
bool com(sz a,sz b){
if(a.zhi!=b.zhi)
return a.zhi>b.zhi;
else return a.wz<b.wz;
}
int main()
{
    int i,j,m,n,i2,i3,i4,i1;
    cin>>n>>m;
    memset(js,0,sizeof(js));
    if(n==1)
    {cin>>x>>y;printf("1\n");}
    else if(n==2)
    {
        x=0,y=0;
        for(i=1;i<=2;i++)
        scanf("%lld",&a[i]);
        for(i=1;i<=2;i++)
        scanf("%lld",&b[i]);
        b1[1][1]=b[1];b1[1][2]=b[2];
        b1[2][1]=b[2];b1[2][2]=b[1];
        if(m==1)
        {
            for(i=1;i<=2;i++)
            {
                x=a[1]+b1[i][1];
                y=a[2]+b1[i][2];
                if(x>=y){js[1][1]++;js[2][2]++;}
                else {js[1][2]++;js[2][1]++;}
            }
        }
        if(m==2)
        {
            for(i=1;i<=2;i++)
            for(i1=1;i1<=2;i1++)
            {
                x=a[1]+b1[i][1]+b1[i1][1];
                y=a[2]+b1[i][2]+b1[i1][2];
                if(x>=y){js[1][1]++;js[2][2]++;}
                else {js[1][2]++;js[2][1]++;}
            }
        }
        if(m==3)
        {
            for(i=1;i<=2;i++)
            for(i1=1;i1<=2;i1++)
            for(i2=1;i2<=2;i2++)
            {
                x=a[1]+b1[i][1]+b1[i1][1]+b1[i2][1];
                y=a[2]+b1[i][2]+b1[i1][2]+b1[i2][2];
                if(x>=y){js[1][1]++;js[2][2]++;}
                else {js[1][2]++;js[2][1]++;}
            }
        }
        if(m==4)
        {
            for(i=1;i<=2;i++)
            for(i1=1;i1<=2;i1++)
            for(i2=1;i2<=2;i2++)
            for(i3=1;i3<=2;i3++)
            {
                x=a[1]+b1[i][1]+b1[i1][1]+b1[i2][1]+b1[i3][1];
                y=a[2]+b1[i][2]+b1[i1][2]+b1[i2][2]+b1[i3][2];
                if(x>=y){js[1][1]++;js[2][2]++;}
                else {js[1][2]++;js[2][1]++;}
            }
        }
       for(i=1;i<=n;i++)
       {for(j=1;j<n;j++)printf("%lld ",js[i][j]);printf("%lld\n",js[i][n]);}
    }
    else if(n==3)
    {
        x=0,y=0;
        for(i=1;i<=3;i++)
        scanf("%lld",&a[i]);
        for(i=1;i<=3;i++)
        scanf("%lld",&b[i]);
        b1[1][1]=b[1];b1[1][2]=b[2];b1[1][3]=b[3];
        b1[2][1]=b[1];b1[2][2]=b[3];b1[2][3]=b[2];
        b1[3][1]=b[2];b1[3][2]=b[1];b1[3][3]=b[3];
        b1[4][1]=b[2];b1[4][2]=b[3];b1[4][3]=b[1];
        b1[5][1]=b[3];b1[5][2]=b[2];b1[5][3]=b[1];
        b1[6][1]=b[3];b1[6][2]=b[1];b1[6][3]=b[2];
        if(m==1)
        {
            for(i=1;i<=6;i++)
            {
                x=a[1]+b1[i][1];
                y=a[2]+b1[i][2];
                z=a[3]+b1[i][3];
                cz[0].wz=1;cz[0].zhi=x;
                cz[1].wz=2;cz[1].zhi=y;
                cz[2].wz=3;cz[2].zhi=z;
                sort(cz,cz+3,com);
                for(j=1;j<=3;j++)
                js[cz[j-1].wz][j]++;
            }
        }
        if(m==2)
        {
            for(i=1;i<=6;i++)
            for(i1=1;i1<=6;i1++)
            {
                x=a[1]+b1[i][1]+b1[i1][1];
                y=a[2]+b1[i][2]+b1[i1][2];
                z=a[3]+b1[i][3]+b1[i1][3];
                cz[0].wz=1;cz[0].zhi=x;
                cz[1].wz=2;cz[1].zhi=y;
                cz[2].wz=3;cz[2].zhi=z;
                sort(cz,cz+3,com);
                for(j=1;j<=3;j++)
                js[cz[j-1].wz][j]++;
            }
        }
        if(m==3)
        {
            for(i=1;i<=6;i++)
            for(i1=1;i1<=6;i1++)
            for(i2=1;i2<=6;i2++)
            {
                x=a[1]+b1[i][1]+b1[i1][1]+b1[i2][1];
                y=a[2]+b1[i][2]+b1[i1][2]+b1[i2][2];
                z=a[3]+b1[i][3]+b1[i1][3]+b1[i2][3];
                cz[0].wz=1;cz[0].zhi=x;
                cz[1].wz=2;cz[1].zhi=y;
                cz[2].wz=3;cz[2].zhi=z;
                sort(cz,cz+3,com);
                for(j=1;j<=3;j++)
                js[cz[j-1].wz][j]++;
            }
        }
        if(m==4)
        {
            for(i=1;i<=6;i++)
            for(i1=1;i1<=6;i1++)
            for(i2=1;i2<=6;i2++)
            for(i3=1;i3<=6;i3++)
            {
                x=a[1]+b1[i][1]+b1[i1][1]+b1[i2][1]+b1[i3][1];
                y=a[2]+b1[i][2]+b1[i1][2]+b1[i2][2]+b1[i3][2];
                z=a[3]+b1[i][3]+b1[i1][3]+b1[i2][3]+b1[i3][3];
                cz[0].wz=1;cz[0].zhi=x;
                cz[1].wz=2;cz[1].zhi=y;
                cz[2].wz=3;cz[2].zhi=z;
                sort(cz,cz+3,com);
                for(j=1;j<=3;j++)
                {
                    js[cz[j-1].wz][j]++;
                }
            }
        }
       for(i=1;i<=n;i++)
       {for(j=1;j<n;j++)printf("%lld ",js[i][j]);printf("%lld\n",js[i][n]);}
    }
    else if(n==4)
    {
        x=1,y=0,z=0,q=0;
        for(i=1;i<=4;i++)
        scanf("%lld",&a[i]);
        for(i=1;i<=4;i++)
        scanf("%lld",&b[i]);
        for(i=1;i<=4;i++)
        for(i1=1;i1<=4;i1++)
        if(i1==i)continue;
        else
        for(i2=1;i2<=4;i2++)
        if(i2==i1||i2==i)continue;
        else
        for(i3=1;i3<=4;i3++)
        if(i3==i||i3==i1||i3==i2)continue;
        else
        {
          b1[x][1]=b[i];
          b1[x][2]=b[i1];
          b1[x][3]=b[i2];
          b1[x][4]=b[i3];
          x++;
        }
        if(m==1)
        {
            for(i=1;i<=24;i++)
            {
                x=a[1]+b1[i][1];
                y=a[2]+b1[i][2];
                z=a[3]+b1[i][3];
                q=a[4]+b1[i][4];
                cz[0].wz=1;cz[0].zhi=x;
                cz[1].wz=2;cz[1].zhi=y;
                cz[2].wz=3;cz[2].zhi=z;
                cz[3].wz=4;cz[3].zhi=q;
                sort(cz,cz+4,com);
                for(j=1;j<=4;j++)
                js[cz[j-1].wz][j]++;
            }
        }
        if(m==2)
        {
            for(i=1;i<=24;i++)
            for(i1=1;i1<=24;i1++)
            {
                x=a[1]+b1[i][1]+b1[i1][1];
                y=a[2]+b1[i][2]+b1[i1][2];
                z=a[3]+b1[i][3]+b1[i1][3];
                q=a[4]+b1[i][4]+b1[i1][4];
                cz[0].wz=1;cz[0].zhi=x;
                cz[1].wz=2;cz[1].zhi=y;
                cz[2].wz=3;cz[2].zhi=z;
                cz[3].wz=4;cz[3].zhi=q;
                sort(cz,cz+4,com);
                for(j=1;j<=4;j++)
                js[cz[j-1].wz][j]++;
            }
        }
        if(m==3)
        {
            for(i=1;i<=24;i++)
            for(i1=1;i1<=24;i1++)
            for(i2=1;i2<=24;i2++)
            {
                x=a[1]+b1[i][1]+b1[i1][1]+b1[i2][1];
                y=a[2]+b1[i][2]+b1[i1][2]+b1[i2][2];
                z=a[3]+b1[i][3]+b1[i1][3]+b1[i2][3];
                q=a[4]+b1[i][4]+b1[i1][4]+b1[i2][4];
                cz[0].wz=1;cz[0].zhi=x;
                cz[1].wz=2;cz[1].zhi=y;
                cz[2].wz=3;cz[2].zhi=z;
                cz[3].wz=4;cz[3].zhi=q;
                sort(cz,cz+4,com);
                for(j=1;j<=4;j++)
                js[cz[j-1].wz][j]++;
            }
        }
        if(m==4)
        {
            for(i=1;i<=24;i++)
            for(i1=1;i1<=24;i1++)
            for(i2=1;i2<=24;i2++)
            for(i3=1;i3<=24;i3++)
            {
                x=a[1]+b1[i][1]+b1[i1][1]+b1[i2][1]+b1[i3][1];
                y=a[2]+b1[i][2]+b1[i1][2]+b1[i2][2]+b1[i3][2];
                z=a[3]+b1[i][3]+b1[i1][3]+b1[i2][3]+b1[i3][3];
                q=a[4]+b1[i][4]+b1[i1][4]+b1[i2][4]+b1[i3][4];
                cz[0].wz=1;cz[0].zhi=x;
                cz[1].wz=2;cz[1].zhi=y;
                cz[2].wz=3;cz[2].zhi=z;
                cz[3].wz=4;cz[3].zhi=q;
                sort(cz,cz+4,com);
                for(j=1;j<=4;j++)
                js[cz[j-1].wz][j]++;
            }
        }
      for(i=1;i<=n;i++)
       {for(j=1;j<n;j++)printf("%lld ",js[i][j]);printf("%lld\n",js[i][n]);}
    }
    return 0;
}

写完这个绝对需要惊人的毅力,对我们那时候简直是劝退的节奏啊,不得不佩服,令之前思路一复杂的时候就想放弃治疗的我自惭形秽。路漫漫其修远兮,加油QWQ。

发布了34 篇原创文章 · 获赞 26 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/sinat_40471574/article/details/89790495