距离noip2018提高组的比赛还有三个月,然而今天却卡在这两个普及-的题上。。。。。。(其实就是我 太菜了)
先看第一题 洛谷P1433吃奶酪
题目描述: 房间里放着n块奶酪。一只小老鼠要把它们都吃掉,问至少要跑多少距离?老鼠一开始在(0,0)点处。
输入格式: 第一行一个数n (n<=15)
接下来每行2个实数,表示第i块奶酪的坐标。
两点之间的距离公式: sqrt((x1-x2)(x1-x2)+(y1-y2)(y1-y2))
输出格式:
一个数,表示要跑的最少距离,保留2位小数。
输入样例#1:
4
1 1
1 -1
-1 1
-1 -1
输出样例#1:
7.41
这是一道比较裸的dfs题了,首先,为了方便在搜索中便于计算,可以先把任意两点间的距离存储下来;
定义一个数组jul,jul [ i ][ j ] 表示第i块奶酪到第j块奶酪之间的距离,在输入的时候就顺便操作了,但是要注意,别忘了把(0,0)和其他点的距离存上,因为小老鼠是从(0,0)开始的;
然后就是dfs了,但是如果不剪枝的话复杂度在15!左右,会tle,所以要剪枝;
只需要一个非常简单的剪枝就可以啦,用now来记录当前走过的距离,ans记录已经找到的最短距离,当now>ans的时候直接return,能节省不少时间;
上代码QwQ
#include<bits/stdc++.h> //懒人(菜鸡)必备万能头文件
using namespace std;
struct mp{
double x,y;
}a[16]; //用a数组来记录每个点的坐标(本菜鸡喜欢用结构体)
int n,t;
double jul[16][16],now,ans=9999999;
bool b[16];
void dfs(int x)
{
if(now>ans)return; //剪枝
if(t==n){
ans=min(now,ans);
return;
}
for(int i=1;i<=n;i++)
if(!b[i])
{
b[i]=true;
now+=jul[x][i];
t++;
dfs(i);
b[i]=false; //回溯
now-=jul[x][i];
t--;
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lf%lf",&a[i].x,&a[i].y);
a[0].x=0;a[0].y=0; //好像没用的初始化
for(int i=0;i<=n;i++)
for(int j=0;j<=n;j++)
{
double x1=a[i].x,x2=a[j].x,y1=a[i].y,y2=a[j].y;
jul[i][j]=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
jul[j][i]=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
//记录i和j之间的距离
}
dfs(0);
printf("%.2f",ans);
return 0;
}
本题完美结束~
第二题:
先描述一下我看到这个普及-的题后的心情
这只是普及-的题啊,这难度的题做不出来还比个啥?
一中的男人绝不能轻易认输。。。。。。
然而————在尝试着写了代码以后,我还是不得不认输了。。。
呜呜呜……嘤嘤嘤……我好菜啊……
于是,诚实(虚伪)的我默默地点开了题解……
借鉴了一下大佬的思路,但是
代码是我自己写的!!!
代码是我自己写的!!!
代码是我自己写的!!!
好了,在扯了一阵子以后,开始讲题;
题目描述
一个N×M 的由非负整数构成的数字矩阵,你需要在其中取出若干个数字,使得取出的任意两个数字不相邻(若一个数字在另外一个数字相邻 88 个格子中的一个即认为这两个数字相邻),求取出数字和最大是多少。
输入输出格式
输入格式: 第1行有一个正整数 T ,表示了有 T 组数据。
对于每一组数据,第一行有两个正整数 N 和 M ,表示了数字矩阵为 N 行 M 列。
接下来 N 行,每行 M 个非负整数,描述了这个数字矩阵。
输出格式: T 行,每行一个非负整数,输出所求得的答案。
思路:从上往下,从左往右,一个一个地搜;
用bool b[7][7]数组来记录(i,j)点是否被取过;判断一个点是否可以取,就看看它附近已经搜到过的点是否被取过,如果附近有被取过的点就继续往后搜,如果没有就取这个点的数,再继续搜;
这个代码中,坐标轴是这样的:
上代码
#include<bits/stdc++.h>
using namespace std;
int l,t,a[7][7],n,m,now=0,ans[25],sum=0,tt;
bool b[7][7],pd;
void dfs(int x,int y,int z)
{
if(x>n){
sum=max(z,sum);
return;
}
int xl=x,yl=y+1;
if(yl>m){
xl++;yl=1;
}
if(!b[x-1][y]&&!b[x][y-1]&&!b[x-1][y-1]&&!b[x-1][y+1])
{
//如果他上面的所有已搜的点没有被取的,就取这个点
b[x][y]=1;
dfs(xl,yl,z+a[x][y]);//继续搜(更新z的值)
b[x][y]=0;
}
dfs(xl,yl,z);//否则跳过(即不更新z的值),继续搜
}
int main()
{
scanf("%d",&l);
while(l--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&a[i][j]);
dfs(1,0,0);
printf("%d\n",sum);
sum=0;
}
return 0;
}
/*
1
2 2
3 4
1 1
*/
最后感谢红名题解大佬 Harry_Potter