day2018.6.23模拟赛总结

emmm...今天的题考的不是很好,T2莫名挂机.

T1:

题目大意:以最简分数的形式给出一个时钟上时针与分针的夹角,时针与秒针的夹角,分针与秒针的夹角,求出所有满足条件的时间.

emmm...大水题,直接暴力枚举用double存分数水过.

考场AC代码:

#include<bits/stdc++.h>
  using namespace std;
#define ACF inline void
typedef long long LL;
typedef double LD;
const LD eps=0.0000001;
int a1,b1,a2,b2,a3,b3,T,s,h,m,sum;
LD x,y,z;
struct node{
  int x,y,z;
}q[1000000];
ACF into(){
  scanf("%d/%d%d/%d%d/%d",&a1,&b1,&a2,&b2,&a3,&b3);
  x=1.0*a1/b1;y=1.0*a2/b2;z=1.0*a3/b3;
}
bool is(double a,double b){
  if (fabs(a-b)<=eps) return true;
  else return false;
}
bool check(int a,int b,int c){
  LD a1,a2,a3;
  a3=c*6.0;
  a2=b*6.0+c*0.1;
  a1=a*30.0+b*0.5+c*(0.5/60.0); 
  if ((is(fabs(a1-a2),x)||is(360.0-fabs(a1-a2),x))&&(is(fabs(a1-a3),y)||is(360.0-fabs(a1-a3),y))&&(is(fabs(a2-a3),z)||is(360.0-fabs(a2-a3),z))) return true;
  else return false;
}
ACF work(){
  sum=0;
  for (h=0;h<12;h++)
    for (m=0;m<60;m++)
      for (s=0;s<60;s++)
        if (check(h,m,s))
          q[++sum].x=h,q[sum].y=m,q[sum].z=s;
}
ACF outo(){
  printf("%d\n",sum);
  for (int i=1;i<=sum;i++){
    if (q[i].x<10) printf("0");
    printf("%d",q[i].x);
    putchar(':');
    if (q[i].y<10) printf("0");
    printf("%d",q[i].y);
    putchar(':');
    if (q[i].z<10) printf("0");
    printf("%d",q[i].z);
    putchar('\n');
  }
}
int main(){
  //freopen("clock.in","r",stdin);
  //freopen("clock.out","w",stdout);
  scanf("%d",&T);
  while (T--){
    into();
    work();
    outo();
  }
  return 0;
}

T2:

题目大意:

有一张n个点m条边的无向图,点从1到n编号,边权均为1.

定义一条路径为另一条一条路径的路径子序列,当且仅当以下两条件同时满足:

1、起始点与终点和另一条路径一样.

2、当前序列是的另一条路径的子序列.

现在,给定一条从点1到点n的路径,你的任务就是找到该路径中点数最少的路径子序列,为了方便,你只需要输出它的长度即可.

这道题用O(n)或O(nlog(n))的算法做就可以了.

考场上我想了一个DP,思路是这样的:

由于边都是双向边,也就是说我们可以双向行走,而题目要求的是子序列,所以我们只要存的非原始路径边(x,y)只有当x和y都在原始路径中才要存,求存的时候应与原始路径的顺序相同.

然后我们就可以用f[i]表示走到原始路径上第i个点的最短路径长度.

那么考场40分代码如下:

#include<bits/stdc++.h>
  using namespace std;
#define ACF inline void
const int N=50000;
const int M=200000; 
int n,m,k,a[N+1],f[N+1],wh[N+1],top;
struct seg{
  int l,r;
}e[M+1];
ACF into(){
  top=0; 
  scanf("%d%d%d",&n,&m,&k);
  int x,y;
  for (int i=1;i<=k+1;i++){
    scanf("%d",&x);
    wh[x]=i;
  }
  for (int i=1;i<=m-k;i++){
    scanf("%d%d",&x,&y);
    if (!wh[x]||!wh[y]) continue;
    if (wh[x]>wh[y]) swap(x,y);
    e[++top].l=wh[x];e[top].r=wh[y];
  }
}
bool cmp(seg a,seg b){
  return a.r<b.r;
}
ACF work(){
  sort(e+1,e+1+top,cmp);
  int j=1;
  for (int i=2;i<=k+1;i++){
    f[i]=f[i-1]+1;
    for (;e[j].r==i;j++)
      f[i]=min(f[i],f[e[j].l]+1);
  }
}
ACF outo(){
  printf("%d\n",f[k+1]);
}
int main(){
  //freopen("seqpath.in","r",stdin);
  //freopen("seqpath.out","w",stdout);
  int T;
  scanf("%d",&T);
  while (T--){
    into();
    work();
    outo();
  }
  return 0;
}

DP莫名错误不知所措...

突然发现自己忘了清空数组...

改完AC代码如下:

#include<bits/stdc++.h>
  using namespace std;
#define ACF inline void
const int N=50000;
const int M=200000; 
int n,m,k,f[N+1],wh[N+1],top;
struct seg{
  int l,r;
}e[M+1];
ACF into(){
  memset(wh,0,sizeof(wh));
  memset(f,0,sizeof(f));
  top=n=m=k=0;
  memset(e,0,sizeof(e));
  scanf("%d%d%d",&n,&m,&k);
  int x,y;
  for (int i=1;i<=k+1;i++){
    scanf("%d",&x);
    wh[x]=i;
  }
  for (int i=1;i<=m-k;i++){
    scanf("%d%d",&x,&y);
    if (x==y) continue;
    if (!wh[x]||!wh[y]) continue;
    if (wh[x]>wh[y]) swap(x,y);
    e[++top].l=wh[x];e[top].r=wh[y];
  }
}
bool cmp(seg a,seg b){
  return a.r<b.r;
}
ACF work(){
  sort(e+1,e+1+top,cmp);
  int j=1;
  f[1]=0;
  for (int i=2;i<=k+1;i++){
    f[i]=f[i-1]+1;
    for (;e[j].r==i;j++)
      f[i]=min(f[i],f[e[j].l]+1);
  }
}
ACF outo(){
  printf("%d\n",f[k+1]);
}
int main(){
  //freopen("seqpath.in","r",stdin);
  //freopen("seqpath.out","w",stdout);
  int T;
  scanf("%d",&T);
  while (T--){
    into();
    work();
    outo();
  }
  return 0;
}

T3:

题目大意:

平面上有n个人,每个人所在的位置可以用一个坐标(x,y)表示,其中x,y均为整数,一个人每次可以选择上下左右任意一个方向走一步,其代价为1,即(x,y)可以变为(x+1,y)、(x-1,y)、(x,y-1)、(x,y+1).

同时,定义一个位置集S是连通的当且仅当S中的任意两个位置都可以只经过S中的位置互相到达.

给定n个人所在的坐标,求使得n个人所在位置两两不同,且所在的位置集合连通的最小总代价.

一看不会,果断放弃.

推了一通n<=3的情况最终放弃.

正解是各种用贪心去中位数然后暴力枚举在这个中位数附近.

具体各类操作看每个函数的含义.

AC代码如下:

#include<bits/stdc++.h>
  using namespace std;
#define ACF inline void
typedef long long LL;
const int x_[4]={0,1,0,-1},y_[4]={1,0,-1,0};
const int N=6;
const LL INF=10000000000000000;
int n,mx,my,px[N+5],py[N+5],fx[N+5],fy[N+5],ex[N*4+5],ey[N*4+5];
bool v[N*3+5][N*3+5];
//mx,my分别表示横纵坐标的中位数,fx,fy数组表示每个人所在的原始横纵坐标
//px,py分别表示每个人要到达的终点位置的坐标,ex,ey分别表示终点枚举的几个可供选择的点 
void mid(){      //取横坐标的中位数与纵坐标的中位数 
  int x[N+5],y[N+5],u=(n+1)/2,d=n/2+1;
  for (int i=1;i<=n;i++)
    x[i]=fx[i],y[i]=fy[i];
  sort(x+1,x+1+n);sort(y+1,y+1+n);
  mx=(x[u]+x[d])/2;my=(y[u]+y[d])/2;
}
LL calc(){      //暴力枚举排列判断哪个位置匹配哪个人 
  int per[N+5]={0};
  LL ans=INF;
  for (int i=1;i<=n;i++) per[i]=i;
  do{      //用do-while是因为while(next_permutation)会跳过初始序列 
    LL s=0LL;
    for (int i=1;i<=n;i++)
      s+=abs(fx[per[i]]-px[i])+abs(fy[per[i]]-py[i]);      //计算当前情况下的行走步数 
    ans=min(ans,s);
  }while (next_permutation(per+1,per+1+n));      //枚举全排列 
  return ans;
}
LL Try(int t,int s,int e){
  if (t>n) return calc();
  LL ans=INF;
  for (int i=s;i<=e;i++){
    px[t]=ex[i];py[t]=ey[i];      //暴力枚举确定终点位置
    int ne=e;
    for (int d=0;d<4;d++)
      if (!v[px[t]+x_[d]+N][py[t]+y_[d]+N]){      //若这个点未被占领
        ex[++ne]=px[t]+x_[d],ey[ne]=py[t]+y_[d];
        v[ex[ne]+N][ey[ne]+N]=1;
      }      //暴力打标记 
    ans=min(ans,Try(t+1,i+1,ne));      //往下递归 
    for (int i=e+1;i<=ne;i++)
      v[ex[i]+N][ey[i]+N]=0;      //回溯 
  }
  return ans;
}
ACF into(){
  mx=my=0;
  memset(px,0,sizeof(px));
  memset(py,0,sizeof(py));
  memset(fx,0,sizeof(fx));
  memset(fy,0,sizeof(fy));
  //初始化清空数组
  scanf("%d",&n);
  for (int i=1;i<=n;i++)
    scanf("%d%d",&fx[i],&fy[i]);
  mid();
}
ACF work(){
  for (int i=1;i<=n;i++)
    fx[i]-=mx,fy[i]-=my;      //计算到中位数的需要的偏移量 
  v[N][N]=1;
  for (int i=1;i<=4;i++){
    ex[i]=x_[i-1],ey[i]=y_[i-1];      //枚举4个点每个终点位置 
    v[ex[i]+N][ey[i]+N]=1;
  }
}
ACF outo(){
  printf("%lld\n",Try(2,1,4));      //dfs暴力求解 
}
int main(){
  //freopen("meet.in","r",stdin);
  //freopen("meet.out","w",stdout); 
  int T;
  scanf("%d",&T);
  while (T--){
    into();
    work();
    outo();
  }
  return 0;
}

又是一道码农题...

猜你喜欢

转载自blog.csdn.net/hzk_cpp/article/details/80783287