这题的题干很好懂,即给定一个定长的数组,每次将数组中最小的两个数相加并替换数组中原来的两个元素,直到数组中只剩下一个元素,要求输出每一次相加过程的总和,直接模拟即可。
按照此思路模拟,有一点可以优化。由上面对题目整个过程的描述我们可以很容易想到,当数组中只剩下两个元素的时候,就不需要排序了,而这次相加的费用正是数组中全体元素的和。因此,我们可以在输入时就提前计算全体元素的和,然后循环到i小于n减2即可。
下面给出代码:
#include
#include
using namespace std;
int main()
{
int n;
while(cin>>n)
{
int a[n],sum=0; // sum作为总费用
for(int i=0;i<n;i++)
{
cin>>a[i];
sum+=a[i]; //有一组费用我们不难发现,它就是所有元素的和
}
sort(a,a+n);
for(int i=0;i<n-2;i++) //因为我们提前加了所有元素的费用,所以只能加到只剩两个元素时
{
int t=a[i]+a[i+1]; //排序后,前两个一定是最小的,我们的删除操作完全可以变成“数组元素的右移”
sum+=t;
a[i+1]=t; //将最小和赋值给a[i+1],下面再排序
sort(a+i+1,a+n);
}
cout<<sum<<endl;
}
return 0;
}
这道题是一道贪心+模拟,整体思路如下:
1.枚举途中经过的加油站,每经过一个加油站,计算一次花费
2.在一个加油站所需要加的油,就是能够支持它到达下一个油价比它低的加油站的量;
3.如果在这个加油站即使加满油,都不能到达一个比它油价低的加油站,
(1)就把油箱加满,前往能够到达的加油站中油价最低的那个;
(2)或者直接到终点;
4.如果在这个加油站即使加满油,都不能到达任意一个加油站,也不能到达终点城市,说明无解;
第一点:先考虑2再考虑3,2一定划算,且无后续性
第二点:注意不仅要省钱,还要是最近的加油站(尽早省钱美滋滋)
第四点:前提是不省钱,注意要考虑直接到终点的情形
第五点:为什么要加满油?因为这样可以减少在下一个加油站(价格更贵)所需要加的油量。
下面给出代码:
#include
#include
#include
using namespace std;
double d1,c,d2,n,p1,lc,ans,yx;
struct station
{
double d,p;
}a[10005];
int main()
{
scanf("%lf%lf%lf%lf%lf",&d1,&c,&d2,&p1,&n);
lc=c*d2;//总路程
for(int i=1;i<=n;i++) scanf("%lf%lf",&a[i].d,&a[i].p);
double i=0,yq=p1;
while(i<d1)
{
double t=i+lc,_min=1e9;
int bh=0;
for(int j=1;j<=n;j++)
{//在范围内寻找能省钱且最近的
if(a[j].d>i&&a[j].d<=t&&a[j].d<d1&&a[j].p<yq&&a[j].d<_min)
{
bh=j,_min=a[j].d;
}
}
if(bh!=0) ans+=((a[bh].d-i)*yq-yx)/d2,i=a[bh].d,yq=a[bh].p,yx=0;
//剩余油不可能直接使到达
//不能找到,分为能否直接到达终点以及有无后续加油站两方面同时考虑
else
{
_min=1e9,bh=0;
for(int j=1;j<=n;j++)
{//在范围内寻找最便宜(并不省钱)的加油站
if(a[j].d>i&&a[j].d<=t&&a[j].d<d1&&a[j].p<_min) _min=a[j].p,bh=j;
}
//无后续加油站且无法直接到达终点
if(bh==0&&t<d1)
{
printf("No Solution");
return 0;
}
//能直接到达,最划算
if(t>=d1) {
if(yx<(d1-i)/d2)
{
ans+=((d1-i)/d2-yx)*yq;
}
break;
}
//不能直接到达但有后续加油站,先加满(省钱),记录剩余油的多少
//加满和到最便宜的地方是关键
else
{
ans+=(c-yx)*yq;
yx=c-(a[bh].d-i)/d2;
yq=a[bh].p,i=a[bh].d;
}
}
}
printf("%.2lf",ans);
}
解题思路:
1.Impossible
maamdmaam—>奇数个字符出现的次数为1或0时才能实现回文
统计每个字符出现的次数,如果出现奇数的次数>1时,这时表示不能实现回文;
2.从最后面查找第1个出现的位置
3.将一个字符交换到指定的位置
dmama—>mdama
4.奇数个字符的处理
下面给出代码:
#include
#include
#include
using namespace std;
char arr[8005];
int b[30];
int N,count;
int main()
{
//输入
cin>>N;
for(int i=0;i<N;i++)
{
cin>>arr[i];
b[arr[i]-'a']++;
}
//统计字符串中每个字符出现的次数
//如果字符串中有字符单数的次数>1,表示不可能交换成回文数
for(int i=0,flag=0;i<26;i++)
{
if(b[i]%2==1)
{
if(++flag>1)
{
cout<<"Impossible"<<endl;
return 0;
}
}
}
int start=0,j,flag;
for(int i=0;i<N/2;i++)
{
flag=0;
for(j=N-i-1;j>i;j--)
{
if(arr[i]==arr[j])
{
for(int start=j;start<N-i-1;start++)
{
char temp=arr[start];
arr[start]=arr[start+1];
arr[start+1]=temp;
count++;
}
break;//第一次出现相等的时候
}
}
if(j==i)
{
char temp=arr[i];
arr[i]=arr[i+1];
arr[i+1]=temp;
count++;
flag=1;
}
if(flag==1)
{
i--;
}
}
cout<<count<<endl;
}
贪心题。
思路是是先对两个字符串进行比较,用数组记录下比较的结果,0表示字符相同,1表示字符不同。
用题目给的例子示范,比较结果为:
1000010000
翻动次数就是两个1之间的下标之差。
当然也有些复杂的情况,若比较结果为: 101101100101
你是直接翻动中间的两个“11”处的硬币再解决其它硬币呢(因为翻动相邻的两个硬币只算一次操作),还是按上面的规则依次计算呢?
这道题“贪心”之处就在这里,事实上从左到右依次按上面蓝字的规则累加计数,就可求得最优结果。
下面给出代码:
#include
using namespace std;
int main()
{
char s1[1000];
char s2[1000];
int cr[1000]; //记录两个字符串的比较结果。0为相同,1为不同。
while(cin>>s1)
{
cin>>s2;
int l;
for(l=0;s1[l]!='\0';l++); //计算长度
for(int i=0;i<l;i++) //比较两个字符串,并记录结果
{
if(s1[i]==s2[i])
cr[i]=0;
else
cr[i]=1;
}
int f=-1; //记录标记位
int _count=0;
for(int i=0;i<l;i++)
{
if(cr[i]==1) //检测到一个 1
{
if(f==-1) //如果前面没有记录的1的下标,记录当前1的下标
{
f=i;
}
else //如果前面有一个1了
{
_count+=i-f;
f=-1;
}
}
}
cout<<_count<<endl;
}
return 0;
}
此题难度较低,思路如下:
1. 用bool数组a[][]存下地图上的地雷(是地雷为true,不是地雷为false,初始化全为false)
2. 双重循环枚举数组元素,暴力计算结果。
下面给出代码:
#include
using namespace std;
bool a[105][105];
int n,m;
int main()
{
memset(a,0,sizeof(a));
char tmp;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>tmp;
if(tmp=='*')a[i][j]=1;
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(a[i][j]==1)putchar('*');
else
printf("%d",a[i+1][j+1]+a[i+1][j-1]+a[i+1][j]+a[i][j+1]+a[i][j-1]+a[i-1][j+1]+a[i-1][j]+a[i-1][j-1]);
}
putchar('\n');
}
return 0;
}
这是一道简单的搜索题,把圈外的元素都搜一遍并赋值-1,从一点向四个方向搜索,越界或不等于0时停止;
题意是闭合圈而不是闭合圆,所以不能只设四个角为搜索起点,要把四条边上的所有元素都设置成搜索起点,遇到圈就会return;
现在圈外元素全部为-1,圈内元素为0;圈为1,三级划分已经很明显了,直接按照题意输出就OK;
下面给出代码:
#include
using namespace std;
int n,a[31][31];
void dfs(int x,int y)
{
if (x<1||y<1||x>n||y>n||a[x][y]!=0)return;
a[x][y]=-1;
dfs(x+1,y);
dfs(x-1,y);
dfs(x,y+1);
dfs(x,y-1);
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
cin>>a[i][j];
}
for(int i=1;i<=n;i++)
{
if (a[i][1]!=1) dfs(i,1);
if (a[i][n]!=1) dfs(i,n);
}
for(int i=1;i<=n;i++)
{
if (a[1][i]!=1) dfs(1,i);
if (a[n][i]!=1) dfs(n,i);
}
for (int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if (a[i][j]==-1)
{
cout<<'0'<<' ';
}
else if(a[i][j]==1)
{
cout<<'1'<<' ';
}
else
{
cout<<'2'<<' ';
}
}
cout<<endl;
}
return 0;
}
首先想到这题是一道贪心题,我们要让瘦子们和可以和他组的中的最瘦的人组队,但是如果直接让最瘦的与最胖的组,显然不对,因为这样会导致一些不那么胖的人没法组。
考虑到最多组 n/2 对,于是我们可以把所有人分为前后两段,前面一段最瘦的找后一段中满足条件中最瘦的,这样就可以得到正解了
下面给出代码:
#include
using namespace std;
const int maxn = 5e5+500;
int mp[maxn];
int n,m;
int main(){
scanf("%d",&n);
for(int i=0;i<n;++i) scanf("%d",&mp[i]);
sort(mp,mp+n);
int ans=0;
for(int i=0,j=1;i<n/2;++i){
while(mp[i]*2>mp[j]&&j<n) j++;
if(j>=n) break;
ans++;
j++;
}
printf("%d\n",n-ans);
return 0;
}