Google APAC 2015 RoundC 部分题解.....

A

          题意: 

                   扫雷游戏...知道当点击了一个无雷的格子之后..若该格子相邻八个方向都无雷(也就是数字为0)则会自动的去翻开周围的格子(也就是有时候点一下出来一片)..现在给出一个扫雷的地图...标记了雷的位置..问最少点多少次可以让非雷的格子都翻过来..

          题解:

                   易得...优先点击为0的格子就好..所以把无雷的都取出来..按其数字由小到大排序..然后从头开始点击并且模拟点一片的过程就行...


 program:

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h> 
#include<string>
#include<queue>
#include<map>
#include<algorithm>
#define MAXN 305
#define ll long long
#define oo 1e+10
#define eps 1e-10
using namespace std; 
struct node
{
      int y,x,m;
}P[MAXN*MAXN];
int F[8][2]={{1,0},{-1,0},{1,1},{0,1},{-1,1},{1,-1},{0,-1},{-1,-1}};
char s[MAXN][MAXN]; 
bool cmp(node a,node b)
{
      return a.m<b.m;
}  
void dfs(int y,int x)
{
      int t,m=0;
      if (s[y][x]!='.') return;
      s[y][x]='#';
      for (t=0;t<8;t++)
        if (s[y+F[t][0]][x+F[t][1]]=='*') m++;
      if (m) return;
      for (t=0;t<8;t++)
        dfs(y+F[t][0],x+F[t][1]);
}
int main()
{       
      int C,cases,n,i,j,y,x,t,num,ans;    
      scanf("%d",&C);
      for (cases=1;cases<=C;cases++)
      {
              memset(s,0,sizeof(s));
              scanf("%d",&n);
              for (i=1;i<=n;i++) scanf("%s",s[i]+1);
              num=0;
              for (i=1;i<=n;i++)
                for (j=1;j<=n;j++)
                  if (s[i][j]!='*')
                  {
                          P[++num].m=0;
                          P[num].y=i,P[num].x=j;
                          for (t=0;t<8;t++)
                          {
                                  y=i+F[t][0],x=j+F[t][1];
                                  if (s[y][x]=='*') P[num].m++;
                          } 
                          
                  }
              sort(P+1,P+1+num,cmp),ans=0;
              for (i=1;i<=num;i++)
                if (s[P[i].y][P[i].x]=='.')
                {
                         ans++;
                         if (P[i].m) continue;
                         dfs(P[i].y,P[i].x);
                }
              printf("Case #%d: %d\n",cases,ans);
      }
      return 0;
}

                   

B

          题意: 

                   一个城市的地铁网..有n条线路..对于线路i...每次到站要上地铁需要等固定的Wi时间...并且有Si个站...给出了相邻站所需的时间...地铁网中有些不同线路的不同站之间是有步行通道的..一共有m个步行通道..给出了其连接的两个地铁站以及步行的时间...现在某人从m1条线路的s1站进站出发要到大m2条线路的s2站..问最少的时间..

          题解:

                   构图最短路,值得注意的是进站不一定要上车..比如:

                             2
                             2 100
                            100 
                            2 1
                            1 
                            2
                            1 1 2 1 1
                            2 2 1 2 1
                            1
                            1 1 1 2

                  我的处理方法是,在一个站,进地铁车中和不进地铁车中为两个大点..从没在地铁车中道在地铁车中有边长度为该线路需要等待的时间..从地铁中道没在地铁中有一条边长度为0(下车秒下)...其他的按照题意是在地铁车中还是不在地铁车中构好图就行...


Program:

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h> 
#include<string>
#include<queue>
#include<map>
#include<algorithm>
#define MAXN 100005
#define ll long long
#define oo 1e+9
#define eps 1e-10
using namespace std;    
struct node
{
      int u,v,l,next;
}edge[MAXN];
int P[2][105][1005],Sn[105],W[105],dis[MAXN],En,_next[MAXN],Vn;
bool inQ[MAXN];
queue<int> Q;
void addedge(int u,int v,int l)
{
      edge[++En].u=u,edge[En].v=v,edge[En].l=l;
      edge[En].next=_next[u],_next[u]=En;
}
int ShortestPath(int m1,int s1,int m2,int s2)
{
      int S=P[0][m1][s1],T=P[0][m2][s2],u,v,l,k; 
      memset(dis,0x7f,sizeof(dis));
      memset(inQ,0,sizeof(inQ));
      dis[S]=0,Q.push(S);
      while (!Q.empty())
      {
              u=Q.front(),inQ[u]=false,Q.pop();
              for (k=_next[u];k;k=edge[k].next)
              {
                       v=edge[k].v,l=edge[k].l;
                       if (dis[v]<=dis[u]+l) continue;
                       dis[v]=dis[u]+l;
                       if (!inQ[v])
                       {
                             inQ[v]=true;
                             Q.push(v);
                       }
              }
      }
      if (dis[T]>oo) return -1;
      return dis[T];
}
int main()
{       
      int C,cases,n,m,t,i,j,l,m1,s1,m2,s2,Q,x1,x2,y1,y2; 
      scanf("%d",&C);
      for (cases=1;cases<=C;cases++)
      { 
                printf("Case #%d:\n",cases); 
                scanf("%d",&n),Vn=0,En=0;
                memset(_next,0,sizeof(_next));
                for (t=1;t<=n;t++)
                {
                        scanf("%d%d",&Sn[t],&W[t]);
                        for (i=1;i<=Sn[t];i++) 
                        {
                                P[0][t][i]=++Vn,P[1][t][i]=++Vn;
                                addedge(P[0][t][i],P[1][t][i],W[t]);
                                addedge(P[1][t][i],P[0][t][i],0);
                        }
                        for (i=1;i<Sn[t];i++)
                        {
                                scanf("%d",&l);
                                addedge(P[1][t][i],P[1][t][i+1],l);
                                addedge(P[1][t][i+1],P[1][t][i],l);
                        }
                }
                scanf("%d",&m);
                while (m--)
                {
                        scanf("%d%d%d%d%d",&m1,&s1,&m2,&s2,&l);
                        addedge(P[0][m1][s1],P[0][m2][s2],l);
                        addedge(P[0][m2][s2],P[0][m1][s1],l);
                }
                scanf("%d",&Q);
                while (Q--)
                {
                        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
                        printf("%d\n",ShortestPath(x1,y1,x2,y2));
                }
      }
      return 0;
}


C

          题意: 

                   有一个计算器坏了..操作符只能使用乘号与等于..并且只有某些数字能用(0~9)..输入给出..现在给出一个数问最少需要多少操作得到该数..注意..这种情况..如果需要的数是5..而计算器5也是好的..也必须要两步.5=..

          题解:

                   DP解决了..代表到达某个值的最少操作..值得注意的是..对于每个值有一个是完整的..一种是还是式子..这样分是因为直接在后面加一位时必须保证当前的值是一个完整的数字而不是还没计算的式子...比如可以用3,2,1现在要需要61..不能这样: 3*2然后后面直接连一个1,那样会变成3*21..而不是61..必须3*2=6之后再添加1变为61...

                   大数据没过..不知道怎么了..T_T...


Program:

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h> 
#include<string>
#include<queue>
#include<map>
#include<algorithm>
#define MAXN 1000005
#define ll long long
#define oo 1e+9
#define eps 1e-10
using namespace std;    
int dp[2][MAXN],f[10]; //0分裂的,1完整的 
int main()
{       
      int C,cases,i,X,t;  
      scanf("%d",&C);
      for (cases=1;cases<=C;cases++)
      {
                for (i=0;i<10;i++) scanf("%d",&f[i]);
                scanf("%d",&X);
                memset(dp,0x7f,sizeof(dp)),dp[0][0]=dp[1][0]=0;
                for (i=0;i<=X;i++)
                  if (dp[0][i]<oo)
                  {
                         dp[1][i]=min(dp[1][i],dp[0][i]+1);
                         for (t=0;t<10;t++)
                           if (f[t] && i*10+t<=X)
                             dp[1][i*10+t]=min(dp[1][i*10+t],dp[1][i]+1), //完整的 
                             dp[0][i*10+t]=min(dp[0][i*10+t],dp[1][i*10+t]);
                         if (!i) continue;
                         for (t=X/i;t>=1;t--)
                            if (dp[0][t]<oo)
                               dp[0][t*i]=min(dp[0][t*i],dp[0][i]+dp[0][t]+1);
                  } 
                printf("Case #%d: ",cases);
                if (dp[0][X]>oo) puts("Impossible");
                     else printf("%d\n",dp[0][X]+1);
      }
      return 0;
}

D题主要是写起来麻烦...好不容易写完..也没调出来..时间充裕也是比较简单的....

最后..本次比赛的关键是....翻墙技术哪家强.....


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值