题目:
八皇后问题是在棋盘上放皇后,互相不攻击,求方案。变换一下棋子,还可以有八车问题,八马问题,八兵问题,八王问题,注意别念反。在这道题里,棋子换成车,同时棋盘也得换,确切说,是进行一些改造。比如现在有一张n*n的棋盘,我们在一些格子上抠几个洞,这些洞自然不能放棋子了,会漏下去的。另外,一个车本来能攻击和它的同行同列。现在,你想想,在攻击的过程中如果踩到一个洞,便会自取灭亡。故,车的攻击范围止于洞。
此题,给你棋盘的规模n,以及挖洞情况,求放k个车的方案数(k从0到最多可放车数)
要点总结:
用一个数组去记录放各个数量的车能有的方案数,每次dfs传入横纵坐标以及目前放的车数量,这里要注意一行是可以放多辆车的,所以遍历该横纵坐标后面所有的点,如果符合条件就递归进入。(这种操作就已经包含了选这点与不选这点,因为后面有回溯。
代码:
#include<bits/stdc++.h>
using namespace std;
int n;
vector<vector<int>> board;
vector<vector<bool>> placed;
vector<int> fangan;
int num;
vector<vector<int>> dire={{0,1},{1,0}};
bool isavail(int x,int y){
if(board[x][y]==0) return false;
for(int i=x-1;i>=1;i--){
if(board[i][y]==0) break;
else if(placed[i][y]==true) return false;
}
for(int i=y-1;i>=1;i--){
if(board[x][i]==0) break;
else if(placed[x][i]==true) return false;
}
return true;
}
void dfs(int x,int y,int cur){
fangan[cur]++;
for(int i=x;i<=n;i++){
int startcol=(i==x) ? y+1 : 1;
for(int j=startcol;j<=n;j++){
if(isavail(i,j)){
placed[i][j]=true;
dfs(i,j,cur+1);
placed[i][j]=false;
}
}
}
}
int main(){
cin>>n;
board.resize(n+1,vector<int> (n+1));
placed.resize(n+1,vector<bool> (n+1,false));
fangan.resize(n*n+1,0);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>board[i][j];
}
}
dfs(1,0,0);
int endidx=0;
for(int i=1;i<fangan.size();i++){
if(fangan[i]>0) endidx=i;
}
for(int i=1;i<=endidx;i++){
cout<<fangan[i]<<endl;
}
return 0;
}
题目:
现在,有许多给小孩子玩的数字游戏,这些游戏玩起来简单,但要创造一个就不是那么容易的了。 在这,我们将介绍一种有趣的游戏。
你将会得到N个正整数,你可以将一个整数接在另一个整数之后以制造一个更大的整数。 例如,这有4个数字123, 124, 56, 90,他们可以制造下列整数─ 1231245690, 1241235690, 5612312490, 9012312456, 9056124123....等,总共可以组合出24(4!)种数字。 但是,9056124123是最大的那一个。
你可能会想这是个简单的事情,但对刚有数字概念小孩来说,这会是个简单的任务吗
要点总结:
C++的字符串比较大小已经重写过了,不用自己去遍历。它会先根据长度然后根据字典序,直接比较即可。这里关键是封装一个sort使用的比较方法,把放在前面和其他字符串相加之后结果大的字符串放在前面。一次sort就好获取结果了。
代码:
#include<bits/stdc++.h>
using namespace std;
bool compa(string a,string b){
return a+b>b+a;
}
int main(){
int n;
while(cin>>n){
if(n==0){
break;
}
vector<string> arr(n);
for(int i=0;i<n;i++){
cin>>arr[i];
}
sort(arr.begin(),arr.end(),compa);
string res="";
for(string s : arr){
res=res+s;
}
cout<<res<<endl;
}
return 0;
}
题目:
对于一个给定的长度为N的整数序列A,它的"子序列"的定义是:A中非空的一段连续的元素(整数)。你要完成的任务是,在所有可能的子序列中,找到一个子序列,该子序列中所有元素的和是最大的(跟其他所有子序列相比)。程序要求你输出这个最大值。
要点总结:
不要暴力枚举,采用动态规划的思想,遍历每个位置,以这个位置为结尾的子序列的最大值为max(这个位置的值,这个位置的值加上以上个位置为结尾的子序列的最大值),因为以它为结尾可以直接就它一个,或者前面还有,如果前面还有的话一定是上次的最优解才能满足。然后再维护一个全局变量,用每个位置结尾的最大值去更新全局变量。
代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
vector<int> arr(n);
for(int i=0;i<n;i++){
cin>>arr[i];
}
int curmax=arr[0];
int glomax=arr[0];
for(int i=1;i<n;i++){
curmax=max(arr[i],curmax+arr[i]);
glomax=max(glomax,curmax);
}
cout<<glomax;
return 0;
}
题目:
小明的实验室有N台电脑,编号1~N。原本这N台电脑之间有N-1条数据链接相连,恰好构成一个树形网络。在树形网络上,任意两台电脑之间有唯一的路径相连。
不过在最近一次维护网络时,管理员误操作使得某两台电脑之间增加了一条数据链接,于是网络中出现了环路。环路上的电脑由于两两之间不再是只有一条路径,使得这些电脑上的数据传输出现了BUG。
为了恢复正常传输。小明需要找到所有在环路上的电脑,你能帮助他吗?
要点总结:
这里虽然是无向图,但是一样用拓扑排序,只不过是不断找度为1的顶点,找到了删掉与之相关的边,其他的和拓扑排序一样,比较巧妙的思路。
代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
vector<vector<int>> arr(n+1,vector<int>(n+1,0));
vector<int> degree(n+1,0);
for(int i=0;i<n;i++){
int s,e;
cin>>s>>e;
arr[s][e]=1;
arr[e][s]=1;
degree[s]++;
degree[e]++;
}
queue<int> que;
vector<bool> flag(n+1,false);
for(int i=1;i<=n;i++){
if(degree[i]==1){
flag[i]=true;
que.push(i);
}
}
while(!que.empty()){
int cur=que.front();
que.pop();
for(int i=1;i<=n;i++){
if(arr[cur][i]==1){
degree[i]--;
if(degree[i]==1){
flag[i]=true;
que.push(i);
}
}
}
}
for(int i=1;i<=n;i++){
if(!flag[i]){
cout<<i<<" ";
}
}
return 0;
}
英语翻译:
目前主流的序列转换模型依赖于复杂的循环神经网络或者卷积神经网络,其通常包括一个编码器和解码器。性能最优的模型也会是以注意力机制的方式连接编码器和解码器。我们提出了一种新的网络架构,transformer架构。单单依靠注意力机制,完全摈弃了循环神经网络以及卷积神经网络。在两台机器翻译上的任务展现出这些模型的运行不仅更加并行化而且需要更少的时间,在翻译质量上也更好。
