第一题求最大子矩阵和
可以转化成最大子序列和来做,用i,k表示行数,将第i行到第k行每一列数依次相加,存储在数组sum[]中,求出sum[]的最大子序列和。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int n,a[105][105],dp[105],sum[105],max1;
int main()
{
//freopen("D://in.txt","r",stdin);
while(~scanf("%d",&n))
{
max1=-0xFFFFF;
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++)
{
memset(sum,0,sizeof(sum));
for(int k=i;k<n;k++)
{
for(int j=0;j<n;j++)
{
sum[j]+=a[k][j];
dp[j]=-0xFFFFF;
}
dp[0]=sum[0];
max1=max(max1,dp[0]);
fornt j=1;j<n;j++)
{
dp[j]=max(sum[j],dp[j-1]+sum[j]);
max1=max(max1,dp[j]);
}
}
}
printf("%d\n",max1);
}
return 0;
}
第二题给你一个m×n的整数矩阵,在上面找一个x×y的子矩阵,使子矩阵中所有元素的和最大
用二维数组map[i][j]表示前i行第j个数的和,把前i行的和压缩到第i行上。
#include<cstdio>
#include<string.h>
int map[1010][1010];
int main()
{
int t;
int x,y,m,n,a,sum,max0;
scanf("%d",&t);
while(t--)
{
memset(map,0,sizeof(map));
scanf("%d %d %d %d",&m,&n,&x,&y);
for(int i = 1 ; i <= m ; i++)
{
for(int j = 1 ; j <= n ; j++)
{
scanf("%d",&a);
map[i][j]=map[i-1][j]+a; //map[i][j]表示前i行第j个数的和
}
}
max0=0;
for(int i = x ; i <= m ; i++) //i从第x行开始(第x行的值表示序列前x行的和)
{
for(int j = y ; j <= n ; j++)
{
sum=0;
for(int k = j-y+1 ; k <= j ; k++) //控制k的范围为y
{
sum+=(map[i][k]-map[i-x][k]); //求出x*y矩阵的和
}
if(sum > max0)
{
max0=sum;
}
}
}
printf("%d\n",max0);
}
}
第三题Give you three sequences of numbers A, B, C, then we give you a number X. Now you need to calculate if you can find the three numbers Ai, Bj, Ck, which satisfy the formula Ai+Bj+Ck = X.
定义三个数组分别存a,b,c的值,再定义数组d存a和b所有可能的和,用给定的数减去c数组中的数得到k,用二分法在d数组找k值,若能找到输出yes,否则输出no。
#include<cstdio>
#include<algorithm>
using namespace std;
int a[505],b[505],c[505],d[505*505];
int main()
{
int j,l,p,m,n,i,k,t,s,num,r,le,mid,key;
num=0;
while(scanf("%d %d %d",&l,&m,&n)!=EOF)
{
for(i = 0 ; i < l ; i++)
{
scanf("%d",&a[i]);
}
for(i = 0 ; i < m ; i++)
{
scanf("%d",&b[i]);
}
for(i = 0 ; i < n ; i++)
{
scanf("%d",&c[i]);
}
p=0;
for(i = 0 ; i < l ; i++)
{
for(j = 0 ; j < m ; j++)
{
d[p++]=a[i]+b[j];
}
}
sort(c,c+n);
sort(d,d+p);
scanf("%d",&t);
printf("Case %d:\n",++num);
while(t--)
{
scanf("%d",&s);
key=0;
for(i = 0 ; i < n ; i++)
{
k=s-c[i];
le=0;
r=p-1;
while(le <= r)
{
mid=(le+r)/2;
if(k == d[mid])
{
key=-1;
break;
}
if(k > d[mid])
{
le=mid+1;
}
else
{
r=mid-1;
}
}
if(key == -1) break;
}
if(key == -1) printf("YES\n");
else
printf("NO\n");
}
}
}
第四题
若出发的房间号小于到达的房间号,正常记录,否则需要交换一下,也看成是从房间号小的房间移动到大的房间;
出发房间为偶数则减一,结束房间为奇数则加一,想想为什么
#include<iostream>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<sstream>
#include<cmath>
#define NUM 20010
int addTime=10;
using namespace std;
int main()
{
int t,n,low,high,temp,ans,maxNum;
int room[NUM];
cin >> t;
while(t--){
memset(room, 0, sizeof(room));
cin >> n;
maxNum=0;
for(int i=0; i<n; i++){
cin >> low >> high;
if(low > high){
temp = low;
low = high;
high = temp;
}
if(maxNum<high)
maxNum=high;
if(low%2==0)
low-=1;
if(high%2==1)
high+=1;
for(int j=low; j<=high; j++)
room[j] += addTime;
}
ans=0;
for(int i=0; i<=maxNum; i++)
if(room[i]>ans)
ans=room[i];
cout << ans << endl;
}
return 0;
}
第五题1.题意:给定很多间隔,合并间隔,使得合并后间隔最小。
思路:先用sort函数按照间隔前段由小到大排序,然后判断是否可以合并,
#include<stdio.h>
#include<algorithm>
#include<iostream>
using namespace std;
#define max 0x7fffffff;
struct node
{
int start;
int end;
} a[50000];
int cmp(struct node a,struct node b)
{
return a.start<b.start;
}
int main()
{
int n,ta,tb;
scanf("%d",&n);
for(int i=0; i<n; i++)
{
scanf("%d%d",&a[i].start,&a[i].end);
}
sort(a,a+n,cmp);
ta=a[0].start;
tb=a[0].end;
a[n].start=max;
a[n].end=max;
for(int i=1; i<=n; i++)
{
if(tb<a[i].start)
{
printf("%d %d\n",ta,tb);
ta=a[i].start;
tb=a[i].end;
}
/*else if(tb>=a[i].end)
{
tb=a[i].end;
}*/
else if(tb>=a[i].start&&tb<=a[i].end)
{
tb=a[i].end;
}
}
return 0;
}
第六题
题意:假设海岸线是一条无限延伸的直线。陆地在海岸线的一侧,而海洋在另一侧。每一个小的岛屿是海洋上的一个点。雷达坐落于海岸线上,只能覆盖d距离,所以如果小岛能够被覆盖到的话,它们之间的距离最多为d。
题目要求计算出能够覆盖给出的所有岛屿的最少雷达数目。
我们假设岛屿i它的x坐标为island[i][0],而y坐标为island[i][1],那么有以下几种情况是invalide的,即输出-1的情况:
1.island[i][1]<0
2.abs(island[i][1])<d
3.d<0
其他的情况,应该就是正常情况,进入计算最小雷达数目。
如上图,红色的点为岛屿,那么能够覆盖到此岛屿的雷达所在的区间,应该就是以该岛屿为圆心的圆与x轴交点所在的区间。
这样,我们就可以计算出所有岛屿的雷达所在的区间,得到一个区间数组。
我们将这个数组按照区间左部分进行排序,那么重叠部分就表明这些岛屿的雷达可以共用一个。从而计算出最终解。
#include<stdio.h>
#include<limits.h>
#include<math.h>
#define MAXNUM 12701
//以岛屿为圆心,以d为半径做圆;得到各个圆与x轴相交的区间;去掉重复区间,即得到雷达数目
int calMin(int **island,int n,int d);
int main() {
int num = 0;
char s[10];
while(1){
num++;
int n,d,i;
scanf("%d%d",&n,&d);
if(n==0&&d==0){
break;
}
int **island = (int**)malloc(sizeof(int*)*n);
for(i=0;i<n;i++){
island[i] = (int*)malloc(sizeof(int)*2);
scanf("%d%d",&island[i][0],&island[i][1]);
}
//计算最少雷达个数
int min = calMin(island,n,d);
printf("Case %d: %d\n",num,min);
//读取空白行
gets(s);
free(island);
}
system("pause");
return 0;
}
int calMin(int **island,int n,int d){
double *arr = (double*)malloc(sizeof(double)*n*2);
int i,j;
for(i=0;i<n;i++){
if(island[i][1]<0||island[i][1]>d||d<0){
return -1;
}
//计算左右区间
if(abs(island[i][1]-d)<1e-6){
arr[2*i] = island[i][0];
arr[2*i+1] = island[i][0];
}else{
//计算
double x = sqrt(pow(d,2)-pow(island[i][1],2));
arr[2*i] = (double)island[i][0] - x;
arr[2*i+1] = (double)island[i][0] + x;
}
}
//排序
for(i=0;i<n-1;i++){
for(j=0;j<n-i-1;j++){
if(arr[2*j]>arr[2*(j+1)]){
double temp = arr[2*(j+1)];
arr[2*(j+1)] = arr[2*j];
arr[2*j] = temp;
temp = arr[2*(j+1)+1];
arr[2*(j+1)+1] = arr[2*j+1];
arr[2*j+1] = temp;
}
}
}
//去掉重合区间,得到雷达个数
int num = 0;
double right = -1;
for(i=0;i<n;i++){
if(i==0){
num++;
right = arr[2*i+1];
}else{
if(arr[2*i]<=right){
if(arr[2*i+1]<right){
right = arr[2*i+1];
}
continue;
}else{
num++;
right = arr[2*i+1];
}
}
}
return num;
}
第七题题目要求从每一列挑出一个数加起来总和为0,直接暴力解会超时,于是有两种优化的方法,分别是
(1)先将第一二列和第三四列分别加起来求出总和,然后将两组总和排序,一组从低开始,一组从高开始互加;
(2)先将第一二列和第三四列分别加起来求出总和,将其中一组排序后,遍历另外一组,通过二分挑选那个排列好的总和数组来相加
#include<cstdio>
#include<algorithm>
using namespace std;
int a[4001],b[4001],c[4001],d[4001];
int ab[4000*4000+1],cd[4000*4000+1];
int main()
{
int n,i,j,k,num,sum,x;
while (~scanf("%d",&n))
{
for (i=0;i<n;i++)
scanf("%d %d %d %d",&a[i],&b[i],&c[i],&d[i]);
k=0;
for (i=0;i<n;i++){
for (j=0;j<n;j++)
ab[k++]=a[i]+b[j];
}
k=0;
for (i=0;i<n;i++){
for (j=0;j<n;j++)
cd[k++]=c[i]+d[j];
}
sort(ab,ab+n*n);
sort(cd,cd+n*n);
x=n*n-1;sum=0;
for (i=0;i<n*n;i++)
{
while (x>=0&&ab[i]+cd[x]>0)
x--;
if (x<0)
break;
num=x;
while (ab[i]+cd[num]==0&&num>=0)
{
sum++;
num--;
}
}
printf("%d\n",sum);
}
return 0;
}
第八题用一个优先队列进行模拟(priority_queue)order的情况。
先按照截止日期due对Order进行从小到大的排序,用pass表示当前完成最多订单需要的最短的时间,
遍历Order,当pass + order[i].q <= order[i].d的时候,
表示可以正常完成该订单,进队,同时pass += order[i].q,
如果pass + order[i].q > order[i].d的时候,
则需要考虑order[i].q和队列中需要最长时间的订单之间的关系,
如果order[i].q较大,说明该订单不可能完成,否则入队,pass += order[i].q,
然后要减去队列中需要最长时间的订单(即队首),一直贪心,最后留在队列中的订单个数就是保留的订单个数。
#include<cstdio>
#include<queue>
#include<iostream>
#include<cstdlib>
#include<algorithm>
#define N 800000+5
using namespace std;
struct g{
int cost;
int date;
}a[N];
int n;
int cmp(const void *a,const void *b){
return (*(struct g *)a).date>(*(struct g *)b).date?1:-1;
}
int main(){
int i;
while(scanf("%d",&n)==1){
for(i=0;i<n;i++)
scanf("%d%d",&a[i].cost,&a[i].date);
qsort(a,n,sizeof(a[0]),cmp);
priority_queue<int> q;
int ans=0;
for(i=0;i<n;i++){
if(ans+a[i].cost<=a[i].date){
ans+=a[i].cost;
q.push(a[i].cost);
}
else
if(ans+a[i].cost>a[i].date&&!q.empty()&&a[i].cost<q.top()){
ans+=a[i].cost;
q.push(a[i].cost);
}
if(ans>a[i].date){
ans-=q.top();
q.pop();
}
}
printf("%d\n",q.size());
}
return 0;
}