题目描述
jyx和cyy打赌,比谁24点算得快,算得慢的那个人请客。24点的规则是这样的:给定4个1..9的整数,用括号改变运算顺序,通过加、减、乘、除中的一系列运算,得到整数24。注意所有中间结果必须是整数(例如(2*2)/4是允许的,而2*(2/4)是不允许的)。为了赢得这个比赛,请写一个程序帮助我作弊,快速地计算出24点。
输入输出格式
输入格式:一行4个整数,为给定的4个数字。输入数据保证有解。
输出格式:一行,以字符串的形式输出结果。注意将每一步的运算的括号补齐(例如(3+5)+6和3* (5+6))。如果有多种解答,输出字典顺序最小的一个。
输入输出样例
题目很冗杂;
1/关于字典序的问题我们发现对括号有三种种情况:(((a+b)+c)+d)或((a+b)+(c+d))或(a+(b+(c+d))) 然后会发现第一种和第三种其实是完全等效的。左,中,右,三种;字典序优先,所以选择第一种;
那么有两种入选(((a+b)+c)+d)或((a+b)+(c+d));
第一种是从头到尾算下来,第二种先前两个算,接着后两个算,最后两边得到的结果算在一起;
两种情况要分开打,麻烦没办法;
2/数字和运算符交替搜索是很难想到的;dfs中带一个参数是选择是数字还是字符的,如果是ture则为数字,反之为运算符;
3。用了哈希,搜索记录的是运算符的下标;用一个函数来运算;
4/出现不能除进ruturn;
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int q1[20],q2[20];
char hash[5]={0,'*','+','-','/'};
int n[5];int used[5];
int operate(int a,int b,int c)
{
switch(c)
{
case 1:return a*b;
case 2:return a+b;
case 3:return a-b;
case 4:if(a%b==0)return a/b;else return -10;
}
return -10;
}
void dfs1(int u,bool o);
void dfs2(int u,bool o);
int main()
{
for(int i=1;i<=4;i++)scanf("%d",&n[i]);
sort(n+1,n+5);
dfs1(1,1);dfs2(1,1);
return 0;
}
void dfs1(int u,bool o)
{
if(u==8)
{
int ans=operate(q1[1],q1[3],q2[2]);
if(ans==-10)return ;
ans=operate(ans,q1[5],q2[4]);
if(ans==-10)return ;
ans=operate(ans,q1[7],q2[6]);
if(ans==24)
{
printf("(((%d%c%d)%c%d)%c%d)",q1[1],hash[q2[2]],q1[3],hash[q2[4]],q1[5],hash[q2[6]],q1[7]);
exit(0);
}
}
else
if(o)
{
for(int i=1;i<=4;i++)
if(!used[i])
{
q1[u]=n[i];
used[i]=1;
dfs1(u+1,!o);
used[i]=0;//!!!1
}
}
else
{
for(int i=1;i<=4;i++)
{
q2[u]=i;
dfs1(u+1,!o);
}
}
}
void dfs2(int u,bool o)
{
if(u==8)
{
int ans1=operate(q1[1],q1[3],q2[2]);
if(ans1==-10)return ;
int ans2=operate(q1[5],q1[7],q2[6]);
if(ans2==-10)return ;
int ans=operate(ans1,ans2,q2[4]);
if(ans==24)
{
printf("((%d%c%d)%c(%d%c%d))",q1[1],hash[q2[2]],q1[3],hash[q2[4]],q1[5],hash[q2[6]],q1[7]);
exit(0);
}
}
else
if(o)
{
for(int i=1;i<=4;i++)
if(!used[i])
{
q1[u]=n[i];
used[i]=1;
dfs2(u+1,!o);
used[i]=0;
}
}
else
{
for(int i=1;i<=4;i++)
{
q2[u]=i;
dfs2(u+1,!o);
}
}
}
亲手打的,懒得标注了
题目描述
在一个长方形框子里,最多有N(0≤N≤6)个相异的点,在其中任何一个点上放一个很小的油滴,那么这个油滴会一直扩展,直到接触到其他油滴或者框子的边界。必须等一个油滴扩展完毕才能放置下一个油滴。那么应该按照怎样的顺序在这N个点上放置油滴,才能使放置完毕后所有油滴占据的总体积最大呢?(不同的油滴不会相互融合)
注:圆的面积公式V=pi*r*r,其中r为圆的半径。
输入输出格式
输入格式:第1行一个整数N。
第2行为长方形边框一个顶点及其对角顶点的坐标,x,y,x’,y’。
接下去N行,每行两个整数xi,yi,表示盒子的N个点的坐标。
以上所有的数据都在[-1000,1000]内。
输出格式:一行,一个整数,长方形盒子剩余的最小空间(结果四舍五入输出)
输入输出样例
因为没有单独讨论油滴在另一个油滴扩展的圆内的情况,这种情况就不能扩展,不单独讨论会变成负面积
#include<bits/stdc++.h>
using namespace std;
double dis[10][10],x,y,x2,y2,a[10][4];//a为点的坐标,1为横坐标,2为纵坐标,dis油滴间距
double R[100],r,maxn;//r为准备放置的油滴的扩散半径 ,maxn是最大油面积
int vis[100],n;//vis判断是否走过
const double pi=acos(-1);
void dfs(int steps,double s)//steps位当前步数,s为当前面积
{
if(steps==n+1)//油滴放完了
{ //更新最大值
if(s>maxn) maxn=s;}
else
for(int k=1;k<=n;k++)
if(!vis[k])//如果没拜访过
{
//矩形和已放置的油滴约束了r的大小 //fabs绝对值函数可以计算浮点数,好像abs不行
r=fabs(y2-a[k][2]);//纵坐标边框限制
//找到所有限制下的最小半径
if(r>fabs(y-a[k][2]))r=fabs(y-a[k][2]);//另一边
if(r>fabs(x2-a[k][1]))r=fabs(x2-a[k][1]);//其他边框
if(r>fabs(x-a[k][1]))r=fabs(x-a[k][1]);//还是边
for(int i=1;i<=n;i++)
{
if(vis[i])//如果拜访过了
if(r>dis[k][i]-R[i])r=dis[k][i]-R[i];//其他油滴限制,油滴距离减去已存半径
}
r=r<0?0:r; //r不能为负
R[k]=r;//记录半径
//搜索模板
vis[k]=1;
dfs(steps+1,s+pi*r*r);
vis[k]=0;
R[k]=0.0;
}
}
int main()
{
scanf("%d%lf%lf%lf%lf",&n,&x,&y,&x2,&y2);
for(int i=1;i<=n;i++)scanf("%lf%lf",&a[i][1],&a[i][2]);
//预处理出油滴间距dis
for(int i=1;i<=n;i++)
{
for(int j=1;j<=i;j++)
{
dis[i][j]=sqrt(pow(fabs(a[i][1]-a[j][1]),2)+pow(fabs(a[i][2]-a[j][2]),2));//油滴i和油滴j之间的间距,距离公式
dis[j][i]=dis[i][j];//i到j的距离就是j到i的距离
}
}
double S=fabs(x-x2)*fabs(y-y2);//矩形面积
dfs(1,0.0);
printf("%.0lf",floor(S-maxn+0.5));
return 0;
}