网易c++笔试牛牛分田问题

//暴力剪枝,哪位大神有好的方法请告知啊
#include<iostream>
#include<vector>
#define nu 4
#define MIN 10000
using namespace std;
int matrix(int i1, int j1, int i2, int j2, vector<vector<int>> &sum)
{

if (i1==0&&j1==0)return sum[i2-1][j2-1];
if (i1 == 0)return sum[i2 - 1][j2 - 1] - sum[i2 - 1][j1 - 1];
if (j1 == 0)return sum[i2 - 1][j2 - 1] - sum[i1 - 1][j2 - 1];
return sum[i2-1][j2-1] + sum[i1-1][j1-1] - sum[i2-1][j1-1] - sum[i1-1][j2-1];

}
void getsum(int n, int m, vector<vector<int>>&a, vector<vector<int>>&sum)
{
if (a.size() == 0)return ;
sum = a;
for (size_t i = 0; i < sum.size(); i++)
{
for (size_t j =1; j < sum[0].size(); j++)
{
sum[i][j] += sum[i][j - 1];
}
for (size_t j = 0; i>0&&j < sum[0].size(); j++)
{
sum[i][j] += sum[i - 1][j];
}
}
}
int digui(vector<vector<int>>&sum,int r[],int c[],int i,int *max)
{
int local_max = 0;
if (sum.size()==0||i == nu)return MIN;
for (r[i] = r[i - 1] + 1; r[i] <= sum.size() - nu + i;r[i]++)
for (c[i] = c[i - 1] + 1; c[i] <= sum[0].size() - nu + i; c[i]++)
{
int min = MIN;
int tt = i;
if (i == 3)tt++;
for (int k = 1; k <= tt; k++)
{
if (min < *max)break;
for (int m = 1; m <= tt; m++)
{
int temp = matrix(r[k - 1], c[m - 1], r[k], c[m], sum);
if (temp < min)min = temp;
if (min < *max)break;
}
}
if (min < *max)continue;
int t = digui(sum, r, c, i + 1, max);
if (t < min)min = t;
if (min>local_max)local_max = min;
if (i==1&&local_max>*max)*max =local_max;
}
return local_max;

}
int main()
{
int n, m;
vector<vector<int>> a;
cin >> n >> m;
for (int i = 0; i < n; i++)
{
vector<int>temp(m,0);
int t;
for (int j = 0; j < m; j++)
{
cin >> t;
temp[j] = t;
}
a.push_back(temp);
}
vector<vector<int>> sum;
getsum(n, m, a, sum);
int max=0;
int r[nu+1], c[nu+1];
r[0] = 0;
c[0] = 0;
r[nu] = n;
c[nu] = m;
digui(sum, r, c, 1, &max);
cout << max << endl;
return 0;
}

全部评论
//题目描述:牛牛和15个朋友玩打土豪分田地的游戏,牛牛决定让你来分田地, // 地主的土地可以看成是一个矩形,每个位置有一个价值。分割田地 // 的方法是横竖各切3刀,分成16分,牛牛作为领导干部,总是选择总 // 价值最小的一份田地,你作为牛牛最好的朋友,希望他分得的土地 // 的价值和尽可能大,你知道这个值最大是多少吗? //输入:每个输入包含一个测试用例,第一行包含两个整数n和m,表示矩阵的大小, // 接下来n行每行包含m个0到9的数字,代表每块位置的价值 //输出:输出一行表示牛牛能分得田地的最大值 //题目来源:网易内推c++笔试第三道编程题 #include <iostream> #include <vector> #include <algorithm> using namespace std; int compute_sum(const vector<vector<int> >& A,int a, int b, int c, int d)//左上角坐标(a,c),右下角坐标(b,d) { int sum = 0; for (int i =a ; i <= b; ++i) { for (int j = c; j <= d; ++j) { sum+=A[i][j]; } } return sum; } int max_index(vector<int>& temp)//返回数组中最大元素对应的索引/下标 { int k = 0; int max = temp[0]; for (int i = 1; i < temp.size(); ++i) { if (temp[i]>max) { max = temp[i]; k = i; } } return k; } int get_min(vector<int>& temp)//返回数组中最小元素 { int min = temp[0]; for (int i = 1; i < temp.size(); ++i) { if (temp[i]<min) { min = temp[i]; } } return min; } int get_max(vector<int>& temp)//返回数组中最大元素 { int max = temp[0]; for (int i = 1; i < temp.size(); ++i) { if (temp[i]>max) { max = temp[i]; } } return max; } int X_cut(const vector<vector<int> >& A, vector<int>& X_num, const int& a)//水平方向下刀函数 { int min = 0; int max = 0; vector<int> temp; vector<int> sum;//记录每个块的总价值 int top = 0;//记录子块的起始行号 int tail = 0;//记录子块的末尾行号 cout << "初始长度=" << X_num.size() << endl; if (X_num.size() == 0) { for (int pos = 0; pos <A.size() - 1; ++pos)//切口位置pos的取值范围是[0, A.size() - 2] { sum.push_back(compute_sum(A, 0, pos, 0, A[0].size() - 1)); sum.push_back(compute_sum(A, pos + 1, A.size() - 1, 0, A[0].size() - 1)); min = (sum[0] <= sum[1]) ? sum[0] : sum[1]; cout << "min=" << min << endl; temp.push_back(min); sum.clear(); } X_num.push_back(max_index(temp)); cout <<endl<<endl; if (X_num.size() == a) { int max_min = get_max(temp); return max_min; } temp.clear(); } int flag = 0; while (X_num.size() != a) { for (int pos = 0; pos < A.size() - 1; ++pos) { flag = 0; for (int i = 0; i < X_num.size(); ++i) { if (pos == X_num[i]) { flag = 1; } } if (flag == 1) temp.push_back(0);//将旧位置标记为0,便于查找合适的切口 if (flag == 0)//表示目标切口位置是新位置 { vector<int> temp2(X_num); temp2.push_back(pos); sort(temp2.begin(), temp2.end()); top = 0; tail = temp2[0]; sum.push_back(compute_sum(A, top, tail, 0, A[0].size() - 1)); for (int i = 0; i < temp2.size() - 1; ++i) { top = temp2[i] + 1; tail = temp2[i + 1]; sum.push_back(compute_sum(A, top, tail , 0, A[0].size() - 1)); } top = temp2[temp2.size() - 1] + 1; tail = A.size() - 1; sum.push_back(compute_sum(A, top, tail, 0, A[0].size() - 1)); int min = get_min(sum); temp.push_back(min); cout << "min=" << min << endl; temp2.clear(); sum.clear(); } } X_num.push_back(max_index(temp)); cout << endl<<endl; if (X_num.size() == a) { int max_min = get_max(temp); return max_min; } else { temp.clear(); } } } int Y_cut(const vector<vector<int> >& A, const vector<int>& X_num,vector<int>& Y_num,int b)//竖直方向下刀函数 { int min = 0; int max = 0; vector<int> temp; vector<int> sum;//记录每个块的总价值 int top = 0;//记录子块的起始列号 int tail = 0;//记录子块的末尾列号 cout << "初始长度=" << Y_num.size() << endl; vector<int> temp3(X_num); sort(temp3.begin(),temp3.end()); if (Y_num.size() == 0) { for (int pos = 0; pos <A[0].size() - 1; ++pos)//切口位置pos的取值范围是[0, A[0].size() - 2] { top = 0; tail = temp3[0]; sum.push_back(compute_sum(A, top, tail, 0, pos)); sum.push_back(compute_sum(A, top, tail, pos+1, A[0].size() - 1)); for (int i = 0; i < temp3.size() - 1; ++i) { top = temp3[i] + 1; tail = temp3[i + 1]; sum.push_back(compute_sum(A, top, tail , 0, pos)); sum.push_back(compute_sum(A, top, tail, pos+1, A[0].size() - 1)); } top = temp3[temp3.size() - 1] + 1; tail = A.size() - 1; sum.push_back(compute_sum(A, top, tail, 0, pos)); sum.push_back(compute_sum(A, top, tail, pos+1, A[0].size() - 1)); min = get_min(sum); temp.push_back(min); cout << "min=" << min << endl; sum.clear(); } Y_num.push_back(max_index(temp)); cout <<endl<<endl; if (Y_num.size() == b) { int max_min = get_max(temp); return max_min; } temp.clear(); } int flag = 0; while (Y_num.size() != b) { for (int pos = 0; pos < A[0].size() - 1; ++pos) { flag = 0; for (int i = 0; i < Y_num.size(); ++i) { if (pos == Y_num[i]) { flag = 1; } } if (flag == 1) temp.push_back(0);//将旧位置标记为0,便于查找合适的切口 if (flag == 0)//表示目标切口位置是新位置 { vector<int> temp4(Y_num); temp4.push_back(pos); sort(temp4.begin(), temp4.end()); sum.push_back(compute_sum(A, 0, temp3[0], 0,temp4[0] )); for (int i = 0; i < temp3.size() - 1; ++i) { sum.push_back(compute_sum(A,temp3[i] + 1 ,temp3[i + 1] , 0,temp4[0] )); } sum.push_back(compute_sum(A,temp3[temp3.size() - 1] + 1 ,A.size() - 1 , 0, temp4[0])); for (int j = 0; j < temp4.size() - 1; ++j) { top = temp4[j] + 1; tail = temp4[j + 1]; sum.push_back(compute_sum(A, 0, temp3[0], top,tail )); for (int i = 0; i < temp3.size() - 1; ++i) { sum.push_back(compute_sum(A,temp3[i] + 1 ,temp3[i + 1] , top,tail )); } sum.push_back(compute_sum(A,temp3[temp3.size() - 1] + 1 ,A.size() - 1 , top, tail)); } sum.push_back(compute_sum(A, 0, temp3[0],temp4[temp4.size() - 1] + 1 , A[0].size()-1)); for (int i = 0; i < temp3.size() - 1; ++i) { sum.push_back(compute_sum(A, temp3[i] + 1, temp3[i + 1], temp4[temp4.size() - 1] + 1, A[0].size()-1)); } sum.push_back(compute_sum(A, temp3[temp3.size() - 1] + 1, A.size() - 1, temp4[temp4.size() - 1] + 1, A[0].size()-1)); min=get_min(sum); temp.push_back(min); cout << "min=" << min<< endl; temp4.clear(); sum.clear(); } } Y_num.push_back(max_index(temp)); cout << endl<<endl; if (Y_num.size() == b) { int max_min = get_max(temp); return max_min; } else { temp.clear(); } } } int main() { int n = 0; cout << "请输入矩阵的行数n" << endl; cin >> n; //矩阵行数 int m = 0; cout << "请输入矩阵的列数m" << endl; cin >> m; //矩阵列数 int a = 0; cout << "请输入水平方向需要切的刀数a, a的范围[1,n)" << endl; //a的范围[1,n) cin >> a; //水平方向需要切的刀数 int b = 0; cout << "请输入竖直方向需要切的刀数b, b的范围[1,m)" << endl; //b的范围[1,m) cin >> b; //竖直方向需要切的刀数 vector<vector<int> > A(n); //二维数组来保存矩阵 for (int i = 0; i < n; i++) { A[i].resize(m); } cout << "请以矩阵的形式输入矩阵" << endl; for (int i = 0; i < n; ++i) //初始化二维数组 { for (int j = 0; j < m; ++j) { cin >> A[i][j]; } } cout << "输入的二维数组为" << endl; for (int i = 0; i < n; ++i) //初始化二维数组 { for (int j = 0; j < m; ++j) { cout << " " << A[i][j]; } cout << endl; } vector<int> X_num;//存储水平方向下刀位置 int value=X_cut(A, X_num, a); cout << endl << endl; cout << "下面依次输出水平方向下刀位置" << endl; for (int i = 0; i < X_num.size(); ++i) { cout <<" "<< X_num[i]; } cout << endl << endl << "value=" << value << endl << endl; vector<int> Y_num;//存储竖直方向下刀位置 int value2 = Y_cut(A, X_num,Y_num, b); cout << endl << endl; cout << "下面依次输出竖直方向下刀位置" << endl; for (int i = 0; i < Y_num.size(); ++i) { cout << " " << Y_num[i]; } cout << endl << endl << "value2=" << value2 << endl << endl; cout << "最小的块可能取得的最大值为" << value2 << endl << endl; return 0; } 笔试的时候题目没有看明白,回头想了想,在vs上写出来了,花了不少时间,编译运行成功。因为在VS2013上写的,有一些简单的cout说明语句没有删除,但是结果应该是正确的,程序还打印输出切割方法,感兴趣的大家可以看一下。
点赞 回复 分享
发布于 2016-08-04 11:08
你这ac了没?
点赞 回复 分享
发布于 2016-08-03 21:38
我的想法是,把输入的矩阵一步步变成4*4的。 如果矩阵行数大于4,就寻找价值最小的那一点,将它所在那一行和它上面一行或者下面一行对应列数相加(看最小点上面的点价值小还是下面的点价值小,还要考虑最小点在第一行和最后一行的情况),处理后矩阵从N*M变为(N-1)*M; 如果矩阵的列数大于4,就寻找价值最小的那一点,将它所在那一列和它左边一列或者右边一列对应行数相加,处理后矩阵从N*M变为N*(M-1)。 如果上面两步处理后的矩阵还是大于4*4,则继续处理。 矩阵变成4*4后,价值最小的那一点的价值即为结果。 不知道这个思路有没有漏洞。 我提交的答案忘了处理最小值在第一行或者最后一行和第一列和最后一列的情况,导致会报异常,所以没有AC。
点赞 回复 分享
发布于 2016-08-04 13:45
是在线下做的。。http://blog.csdn.net/lsxpu/article/details/52100370
点赞 回复 分享
发布于 2016-08-04 15:01

相关推荐

11-30 21:28
已编辑
南京市金陵中学 C++
最后以华为13级这个并不那么满意的offer结束支离破碎的秋招。bg:本硕双9电子信息类,非计算机,论文只有一篇ei会议。秋招目标:私企(问就是亲眼所见国企关停)转码前:研一时虽然大部分师兄师姐在转码,但是各种渠道渲染我们的专业很强,当时的想法是不转码肯定能找到满意的私企,然后拿本科毕设投了个ei会议,并开始自己找课题研究(导师放养)。研一下找到方向,研二上在仿真和写论文的时候开始意识到形势不好,越来越多的学长学姐申请华为的对口职位流程挂或只有个别勉强拿到offer,在萌生转码的念头时论文写到一半,于是决定论文写完再转码,觉得论文对找工作有用(现在来看对找开发的工作作用聊胜于无)。论文写完已经是12月中旬,一次次找导师改收到的是一次次拖延,直到3月份一个字没改让我投顶刊我才意识到这一年半的努力在秋招时不可能再转化为成果了。一个408只学过计算机网络,语言只学过c++且期末也只是刚及格的牛马从12月底才开始了转码。转码:算法卷院校卷顶刊没戏,只可能转开发,由于很多学长学姐都转码拿到华为的offer,难度不高,所以我最开始的目标是通过c++技术栈拿下华为并尝试互联网后端。零基础一切都要现学,所以就先从数据结构、操作系统、算法题这些开发类必备的知识学起,寒假开始刷力扣,当时根本不算是刷题,全是在看题解,印象很深刻的是第一题两数之和折磨了我一下午。三月刷力扣+背408八股,到三月底听计算机的同学说暑期实习后端卷麻了,相反前端今年相对简单,经过几天的考虑,最终决定两线作战:前端和c++,此时认为华为能稳稳作为保底。四月9106匆忙学了html+css+js,五月学了vue就去投实习了,b站腾讯阿里国际美团滴滴给了面试,但只有美团到了终面,结果还因为过于紧张以及没经验说错了话,与offer失之交臂。五月剩下的时间为华为准备了一个c++开源项目,六七月学react并准备了一个前端项目。本来的梦想是秋招签阿里等华为,然而噩梦就要开始了。秋招:先说结论吧,眼高手低,互联网一个都没拿到,老本行拿到某雷达所,前端拿到体面厂和性价比厂,c++拿到某学历厂、华子外包、迪子和两个通信大厂,两个前端base一个杭州一个南京,总包都不到25,c++的几个里华子外包和迪子base深圳,另外三个base上海且薪资降序。八月九月上旬集中投递前端岗位,每天都在笔试测评,但给面试的只有美团京东淘天,美团终面面试官百般刁难,甚至拷打前端发展历史这种问题,寄了之后美团再没捞我,必然是脏了面评,京东一面hr面,拷打我本科成绩和无竞赛奖项,直接寄,淘天二面挂。然后九月中旬发现互联网希望渺茫,慢一步投递了c++相关岗位,华为线下面试一天速通池子后拒了研究所的oc,抱着华为稳了的想法准备结束秋招,结果几天后问面试情况被告知面评非3A。这最后一根稻草压垮了996半年的我,整日的emo和严重的焦虑导致我不停的胡思乱想,加上那几天我的室友和我同一时间投递的三家都有进展甚至oc而我没有任何进展,我在发呆焦虑迷茫中度过了那一周。而一周之后算是有些好消息,开始有offer了,至少不至于毕业即失业。为了给华为留一线生机拒了最早来的一家(听说华为不等这家毁约),体面厂在接受意向后,华为在经过一系列沟通后告知可以给offer,因此未签三方,性价比厂oc后紧接着收到华为通知报批通过,接着就是现在华为第一批开奖了。总结:看着现在同学没有杂七杂八想法单一技术栈allin华为oc14甚至15级很不甘心,回想起来我可能在每个节点都做错了选择:在研一时不做充分调研就对不转码找工作过于自信,不该在只有几个月时间准备的情况下开辟第二战场转前端,不该在找不到暑期实习后还继续梭哈前端,不该在互联网全线溃败时面试华为导致面试官觉得我不够自信……太多的错误导致了这个结局。看好华为的平台以及去上海的意愿让我最后做出了接受13级的选择。回顾这接近19年的学习阶段,我总是在尝试向上卷:中考和全市人竞争重点高中,高考和全省人竞争985,考研更是千军万马过独木桥。我卷进了重点高中,但是我的努力收获的是高三一次比一次差的成绩,高考我考了一个高三从未考到过的成绩,曾经我认为这才是我的真实水平,但是现在我觉得我错了,本科时我卷不过同学,花费几倍于别人的努力却只能勉强达到差不多的水平;考研初试我靠着接近一年的995才收获高分,而准备同样时间的复试我就远远落后于别人;花费同样的时间在科研上也不能获得与别人差不多的成果。曾经我也自命不凡,但我现在意识到自己就是个平凡到不能再平凡的人,我的努力在命运面前仿佛沧海一粟。借用自己很喜欢的一首歌的歌词来结尾吧:“难以释怀的&nbsp;让时间冲淡&nbsp;至少我还在期盼。”希望工作顺利,希望生活如意。
牛客220859485号:唉,加油吧老哥,硕士拿13已经很吃亏了。感觉老哥是选择做错了,卷一卷java去互联网后端没问题的,华子也不是只收c++。all in C++是把路走窄了。
点赞 评论 收藏
分享
11-08 17:36
诺瓦科技_HR
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务