问题一:
P5461 赦免战俘
错误代码:
分析了几个小时压根不会,想从右下角开始递归但是不知道怎么给左上角清0,然后又想从左上角矩阵的右下角开始清零,但还是不知道如何操作(本质就是不会递归。
看了大佬的正确代码后,自己仿造写了一个
#include <iostream>
#include <cmath>
#include <algorithm>
#include <numeric>
#include <iomanip>
#include <cstring>
using namespace std;
int a[1050][1050];
//新知识:memset不能赋值1
//只能0或-1
void Get0(int n,int x,int y)//递归的边长,递归起始坐标
{
if(n==1)
{
//a[x][y] = 0;//递归停止条件当正方形边长只有2
return;
}
for(int i=x;i<=n/2+x-1;i++)//左上角清零
{
for(int j=y;j<=n/2+y-1;j++)
{
a[i][j] = 0;
}
}
Get0(n/2,x,n/2+y);//再将剩余正方形左上角清零
Get0(n/2,n/2+x,y);
Get0(n/2,n/2+x,n/2+y);
}
int main()
{
int n;
cin>>n;
int len = pow(2,n);
for(int i=1;i<=len;i++)
{
for(int j=1;j<=len;j++)
{
a[i][j] = 1;
}
//cout<<endl;
}
Get0(len,1,1);//递归思路,把左上角清零,再递归其他正方形,从左上角开始
//边界条件是边长=2
for(int i=1;i<=len;i++)
{
for(int j=1;j<=len;j++)
{
cout<<a[i][j]<<" ";
}
cout<<endl;
}
}
这个方法就是按照题目意思递归,先将左上角清零,再对剩下的三个矩阵的左上角清零,然后不断往复
这里有几个重要的知识点
- memset只能用来清零或者全部赋值-1,因为它是一个字节一个字节的赋值,而int类型占了四个字节,四个1在int类型里压根不是1,但0和-1是特殊情况
- 递归是要找到中止情况,这里的中止情况是正方形边长为1就停止左上角,再找到递归的操作
但这里也能通过上面一个数字和右上角的数字异或得到规律,这也是利用递推求解吧
问题2:
P2415 集合求和
错误代码:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int f(int a,int b)
{
return a+b+a+b;
}
vector<int> v;
int main()
{
int i;
while(cin>>i)
{
v.push_back(i);
}
int sum=0;
while(v.size()>1)
{
int num1 = v.back();
v.pop_back();
int num2 = v.back();
v.pop_back();
v.push_back(f(num1,num2));
}
for(vector<int>::iterator it = v.begin();it!=v.end();it++)
{
cout<<(*it)<<" ";
}
}
问题分析:
- 我真的太菜了,想法是先求两个数的子集的和,与另一个数求子集的和,但这样会漏算数字,所以是错误的,看了大佬代码发现有规律可循
正确代码
include <iostream>
#include <algorithm>
#include <vector>
#include <numeric>
#include <cmath>
#include <cstdio>
using namespace std;
vector<long long> v;//注意long long
int main()
{
long long i;
while(cin>>i)
{
v.push_back(i);
}
long long sum = (long long)accumulate(v.begin(),v.end(),0);
long long counts = pow(2,v.size()-1);
printf("%ld",sum*counts);
}
规律是杨辉三角每层的和*集合个数即为子集和
- accumulate返回的是int的和,所以需要强制类型转换
- 注意数据范围,int类型会超出范围