先摘一段官话:深度优先搜索(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。