T2题目:
【问题描述】
平面内给 n 个点,记横坐标最小的点为A,最大的点为B,现在小Y想要知道在
每个点经过一次(A 点两次)的情况下从A走到B,再回到A 的最短路径。但他是个强
迫症患者,他有许多奇奇怪怪的要求与限制条件:
1.从A走到B 时,只能由横坐标小的点走到大的点。
2.由B 回到A 时,只能由横坐标大的点走到小的点。
3.有两个特殊点b1 和b2,b1 在 0 到n-1 的路上,b2 在n-1 到0 的路上。
请你帮他解决这个问题助他治疗吧!
【输入格式】
第一行三个整数n,b1,b2,(0<b1,b2<n-1 且b1<>b2)。n 表示点数,从0 到n-1 编
号,b1 和b2 为两个特殊点的编号。
以下n 行,每行两个整数 x、y 表示该点的坐标(0<=x,y<=2000),从0 号点顺序
给出。DoctorGao为了方便他的治疗,已经将给出的点按x 增序排好了。
【输出格式】
输仅一行,即最短路径长度(精确到小数点后面2 位)
【样例输入输出】
paths.in
5 1 3
1 33 4
4 1
7 5
8 3
paths.out
18.18
【样例解释】 最短路径:0->1->4->3->2->0
【数据范围】
20%的数据n<=20
60%的数据n<=300
100%的数据n<=1000
对于所有数据x,y,b1,b2如题目描述.
题解:这是个dp,考场上怎么也没往这方面想。。。我们可以考虑为从1走到n两遍,求两条不相交的路径最小
为了不转移到f[i][i]就让k=max(i,j)+1
然后特殊点什么的特判就好了
代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
struct hh
{
int x,y;
}s[1005];
int n,b1,b2;
bool a[1005];
double f[1005][1005],minn=1000000000;
double ll(int a,int b)
{
return sqrt(double((s[a].x-s[b].x)*(s[a].x-s[b].x)+(s[a].y-s[b].y)*(s[a].y-s[b].y)));
}
int main()
{
freopen("paths.in","r",stdin);
freopen("paths.out","w",stdout);
int i,x,y,j;
scanf("%d%d%d",&n,&b1,&b2);b1++,b2++;
for (i=1;i<=n;i++)
scanf("%d%d",&s[i].x,&s[i].y);//f[i][j]表示第一个点走到i,第二个点走到j的最短距离
memset(f,0x7f,sizeof(f));
f[1][1]=0;
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
if (i!=j || i==1)
{
int k=max(i,j)+1;
if (k==n+1)
{
if (j==n) f[n][n]=min(f[n][n],f[i][j]+ll(i,n));
if (i==n) f[n][n]=min(f[n][n],f[i][j]+ll(j,n));
continue;
}
if (k!=b1) f[i][k]=min(f[i][k],f[i][j]+ll(j,k));
if (k!=b2) f[k][j]=min(f[k][j],f[i][j]+ll(i,k));
}
printf("%.2lf",f[n][n]);
}
T3题目:
时间限制 : 20000MS空间限制 : 265536 KB
问题描述
刚拿到驾照的 KJ 总喜欢开着车到处兜风,玩完了再把车停到阿 Q的停车场里,虽然她对自己停车的水平很有信心,但她还是不放心其他人的停车水平,尤其是 Kelukin。于是,她每次都把自己的爱车停在距离其它车最远的一个车位。KJ觉得自己这样的策略非常科学,于是她开始想:在一个停车场中有一排车位,从左到右编号为 1到 n,初始时全部是空的。有若干汽车,进出停车场共 m次。对于每辆进入停车场的汽车,会选择与其它车距离最小值最大的一个车位,若有多个符合条件,选择最左边一个。KJ想着想着就睡着了,在她一旁的 Kelukin想帮她完成这个心愿,但是他又非常的懒,不愿意自己动手,于是就把这个问题就留给了你:在 KJ 理想的阿 Q 的停车场中,给你车辆进出的操作序列,依次输出每辆车的车位编号。
输入格式
第一行,两个整数 n 和 m,表示停车场大小和操作数;
接下来 m 行,每行两个整数 F 和 x F 是 1表示编号为 x 的车进停车场; F 是 2表示编号为 x 的车出停车场;
保证操作合法,即:出停车场的车一定目前仍在停车场里;停车场内的车不会超过 n;
输出格式
对于所有操作 1,输出一个整数,表示该车车位的编号
样例输入
7 11
1 15
1 123123
1 3
1 5
2 123123
2 15
1 21
2 3
1 6
1 7
1 8
样例输出
1
7
4
2
7
4
1
3
提示
【数据范围】
对 30%的数据n<=1000,m<=1000对
60%的数据 n<=200000,m<=2000
对 100%的数据 n,m<=200000,
车的编号小于等于 10^6
题解:
这个题目是个线段树,其实都是基本的操作,考场上脑子一抽就写挂了。。。。
线段树中维护四个量(全都是所在区间内):l(最左边种树的坐标),r(最右边种树的坐标),mid(最近邻两棵树的最大距离),p(最近邻两棵树的中间位置)
这样每个操作一都可以看成是整个区间的询问:最左边到1是不是最大的距离(答案是1),mid是不是最大距离(答案是p),最右边到r是不是最大距离(答案是n)
这样updata也好维护:now的左就是最左,now的右就是最右,now的mid就是左边的mid,跨边界的mid,和右边的mid比较
操作二是一个添加or删除的过程,删除就是全为0,添加就把所在位置添加进去
代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#define INF 1e9
#define N 200000
using namespace std;
int wz[1000006];
struct hh
{
int l,r,mid,en;
}tree[N*4];
void updata(int now)
{
if (tree[now<<1].l!=0) tree[now].l=tree[now<<1].l; else tree[now].l=tree[(now<<1)|1].l;
if (tree[now<<1|1].r!=0) tree[now].r=tree[now<<1|1].r; else tree[now].r=tree[now<<1].r;
tree[now].mid=tree[now<<1].mid;
tree[now].en=tree[now<<1].en;
if (tree[now<<1|1].l!=0 && tree[now<<1].r!=0)
{
int ss=(tree[now<<1|1].l-tree[now<<1].r)/2;
if (ss>tree[now].mid)
{
tree[now].mid=ss;
tree[now].en=(tree[now<<1|1].l+tree[now<<1].r)/2;
}
}
if (tree[now<<1|1].mid>tree[now].mid)
{
tree[now].mid=tree[now<<1|1].mid;
tree[now].en=tree[now<<1|1].en;
}
}
void work(int now,int l,int r,int mb,int id)
{
if (l==r)
{
if (id==1)
{
tree[now].l=l; tree[now].r=r;
tree[now].mid=0; tree[now].en=0;
}
else
{
tree[now].l=0; tree[now].r=0;
tree[now].mid=0; tree[now].en=0;
}
return;
}
int mid=(l+r)>>1;
if (mb<=mid) work(now<<1,l,mid,mb,id);
else work(now<<1|1,mid+1,r,mb,id);
updata(now);
}
int main()
{
freopen("park.in","r",stdin);
freopen("park.out","w",stdout);
int n,m,i,j;
scanf("%d%d",&n,&m);
for (i=1;i<=m;i++)
{
int id,x;
scanf("%d%d",&id,&x);
if (id==1)
{
if (tree[1].l==0)
{
wz[x]=1;
}
else
{
int sum=-INF;
if (tree[1].l-1>sum)
{
sum=tree[1].l-1; wz[x]=1;
}
if (tree[1].mid>sum)
{
sum=tree[1].mid; wz[x]=tree[1].en;
}
if (n-tree[1].r>sum)
{
sum=n-tree[1].r; wz[x]=n;
}
}
printf("%d\n",wz[x]);
work(1,1,n,wz[x],1);
}
else work(1,1,n,wz[x],2);
}
}