• 2017/10/13模拟赛


    密室逃脱(room
    【问题描述】
    你在玩密室逃脱, 所有房间组成了一个 n m 列的矩阵, 一些
    房间上了锁。 一开始你在某个房间里, 你的目标是逃到边界上(第 1
    行或第 n 行或第 1 列或第 m 列) 的任意一个房间中。 你可以进行若
    干轮操作, 每轮操作你可以先移动至多 k 次, 每次可以移动到四相邻
    (上下左右) 的一个未上锁的房间中, 完成移动后, 你可以再选择至
    k 个房间并解锁这些房间, 然后完成这一轮操作。 你想知道你至少
    要进行几轮操作才可以达成目标。
    【输入格式】
    第一行三个正整数 n,m,k, 意义同问题描述。
    接下来 n 行, 每行 m 个字符, 描述这个矩阵。 若字符为’.’, 表
    示在这个位置上的是一个没上锁的房间; 若字符为’#’, 表示在这个位
    置上的是一个上了锁的房间; 若字符为’S’, 表示在这个位置上的是
    一个没上锁的房间并且是你的初始位置, 保证这样的字符只有一个并
    且不在边界上。
    【输出格式】
    输出一个整数, 表示答案。
    【样例输入】
    5 5 1
    #####
    #...#
    ##S##
    #...#
    #####
    【样例输出】
    2
    【数据范围】
    对于 40%的数据, n,m<=100
    对于 100%的数据, n,m<=1000k<=n*m

    题解:假设我们跑完第一次后,之后就不用考虑锁住的房间啦,所以我们广搜处理出第一次能遍历到的所有点离四周的距离,然后最小值/k+1即可。

    代码如下:

     1 #include<cstdio>
     2 #include<iostream>
     3 #define MN 1005
     4 using namespace std;
     5 const int dx[4]={-1,0,0,1},dy[4]={0,-1,1,0};
     6 char s[1005][1005];
     7 int n,m,k,sx,sy,ans[4],dis[MN][MN],ansx=MN;
     8 bool vis[MN][MN];
     9 struct node{int x,y;}que[MN*MN];
    10 void bfs(){
    11     for(int i=0;i<4;i++) ans[i]=MN;
    12     que[0].x=sx;que[0].y=sy;vis[sx][sy]=1;
    13     int hd=0,tl=0;
    14     while(hd<=tl){
    15         node tmp=que[hd++];
    16         for(int i=0;i<4;i++){
    17             int tx=tmp.x+dx[i],ty=tmp.y+dy[i];
    18             if(vis[tx][ty]||s[tx][ty]=='#'||tx<1||tx>n||ty<1||ty>m) continue;
    19             vis[tx][ty]=1; dis[tx][ty]=dis[tmp.x][tmp.y]+1;
    20             if(dis[tx][ty]<k) que[++tl].x=tx,que[tl].y=ty;
    21             if(tx-1<ans[0]) ans[0]=tx-1;
    22             if(n-tx<ans[1]) ans[1]=n-tx;
    23             if(ty-1<ans[2]) ans[2]=ty-1;
    24             if(n-ty<ans[3]) ans[3]=n-ty;
    25         }
    26     }
    27 }
    28 int main()
    29 {
    30     freopen("room.in","r",stdin);
    31     freopen("room.out","w",stdout);
    32     scanf("%d%d%d",&n,&m,&k);
    33     for(int i=1;i<=n;i++){
    34         scanf("%s",s[i]+1);
    35         for(int j=1;j<=m;j++)if(s[i][j]=='S')sx=i,sy=j;
    36     }bfs();
    37     for(int i=0;i<4;i++) ansx=min(ansx,ans[i]);
    38     printf("%d",1+(ansx%k==0?ansx/k:ansx/k+1));
    39     return 0;
    40 }

    最大割(cut
    【问题描述】
    有一张带权连通无向图,你看它不爽想要删掉若干条边把它分成
    恰好两个连通块, 并且希望删掉的边权和最大, 于是你需要计算出这
    个最大值。
    【输入格式】
    第一行两个正整数 n m, 分别表示点数和边数。
    接下来 m 行, 每行三个正整数 xi,yi,wi, 其中 xi,yi 表示一条边的
    两个端点, wi 表示这条边的边权。
    【输出格式】
    输出一个整数, 表示答案。
    【样例输入】
    3 3
    1 2 1
    2 3 2
    3 1 3
    【样例输出】
    5
    【数据范围】
    对于 30%的数据, n,m<=20
    对于 50%的数据, n,m<=1000
    对于 100%的数据, 2<=n,m<=100000wi<=10000

    题解:最小生成树减去一条最大的边即为答案。

    代码如下:

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<algorithm>
     4 #define MN 100010
     5 using namespace std;
     6 struct edge{int x,y,val;}e[MN];
     7 int n,m,fa[MN],ans,mx,sum;
     8 bool cmp(edge a,edge b){return a.val<b.val;}
     9 int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    10 void unite(int x,int y){
    11     int fx=find(x),fy=find(y);
    12     if(fx==fy) return;
    13     fa[fx]=fy;
    14 }
    15 void kruskal(){
    16     sort(e+1,e+1+m,cmp);
    17     for(int i=1;i<=n;i++) fa[i]=i;
    18     for(int i=1;i<=m;i++){
    19         edge zhouzhenged=e[i];
    20         if(find(zhouzhenged.x)!=find(zhouzhenged.y)){
    21             unite(zhouzhenged.x,zhouzhenged.y);
    22             ans-=zhouzhenged.val; mx=max(mx,zhouzhenged.val);
    23         }
    24     }
    25 } 
    26 int main()
    27 {
    28     freopen("cut.in","r",stdin);
    29     freopen("cut.out","w",stdout);
    30     scanf("%d%d",&n,&m);
    31     for(int i=1;i<=m;i++){
    32         scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].val);
    33         ans+=e[i].val;
    34     }
    35     kruskal();
    36     printf("%d",ans+mx);
    37     return 0;
    38 }

    粉刷匠(painter
    【问题描述】
    作为粉刷界的毒瘤, 你坚信刷墙不需要视力, 于是你总是蒙着眼
    睛刷墙。 正好一位客人需要把墙刷的具有艺术气息, 不要那么规律,
    于是请到了你。 这位客人的墙可以描述成一个 n m 列的矩阵, 一
    些格子已经刷上了颜色, 客人需要你把每行每列都至少刷上一个格
    子。 由于你蒙着眼睛, 所以你每次都会在墙上等概率随机一个格子刷
    上颜色, 无论这个格子是否已经刷过。 你想知道你要完成任务的期望
    刷墙次数。
    【输入格式】
    第一行两个正整数 n m, 意义同问题描述。
    接下来 n 行, 每行 m 0 1 的整数, 若数字为 0 表示这个格
    子还没刷过, 若数字为 1 表示这个格子已经刷过。
    【输出格式】
    输出一个实数, 表示答案。 如果你的答案与标准答案相差不超过
    10-4 , 判为正确。
    【样例输入】
    2 2
    1 1
    0 0
    【样例输出】
    2
    【数据范围】
    对于 30%的数据, n,m<=4
    对于 50%的数据, n,m<=10
    对于 70%的数据, n,m<=100
    对于 100%的数据, n,m<=1000

    题解:期望dp,不会。

  • 相关阅读:
    常见动态规划题目详解
    回溯法常见题目总结
    AWK语法入门
    JavaScript深拷贝—我遇到的应用场景
    git代码版本回退
    Rem实现移动端适配
    Weex了解
    Vue.js入门学习
    今日小结—304状态码,数组去重
    js今日小结—Ajax、前端安全、GET&POST、闭包、HTTPS
  • 原文地址:https://www.cnblogs.com/Beginner-/p/7677519.html
Copyright © 2020-2023  润新知