zoukankan      html  css  js  c++  java
  • 8.10 纪中集训 Day10

    T1洪水

    Description

    一天, 一个画家在森林里写生,突然爆发了山洪,他需要尽快返回住所中,那里是安
    全的。
    森林的地图由R行C列组成,空白区域用点“.”表示,洪水的区域用“*”表示,而
    岩石用“X”表示,另画家的住所用“D”表示,画家用“S”表示。
    有以下几点需要说明:
    1、 每一分钟画家能向四个方向移动一格(上、下、左、右)
    2、 每一分钟洪水能蔓延到四个方向的相邻格子(空白区域)
    3、 洪水和画家都不能通过岩石区域
    4、 画家不能通过洪水区域(同时也不行,即画家不能移到某个格子,该格子在画家达到的同时被洪水蔓延到了,这也是不允许的)
    5、 洪水蔓不到画家的住所。
    给你森林的地图,编写程序输出最少需要花费多长时间才能从开始的位置赶回家中。

    Input

    输入第一行包含两个整数R和C(R,C<=50)。
    接下来R行每行包含C个字符(“.”、“*”、“X”、“D”或“S”)。地图保证只有一个“D”和一个“S”。

    Output

    输出画家最快安全到达住所所需的时间,如果画家不可能安全回家则输出“KAKTUS”。

    Sample Input

    输入1:
    3 3 
    D.* 
    ... 
    .S. 
    
    输入2:
    3 3 
    D.* 
    ...
    ..S
    
    输入3:
    3 6 
    D...*. 
    .X.X.. 
    ....S. 

    Sample Output

    输出1:
    3
    
    输出2:
    KAKTUS 
    
    输出3:
    6

    考场思路/正解

    很裸的BFS,签到题。

    Code

    #include<cstdio>
    #include<algorithm>
    #define MAXN 2525
    #define INF 2e9
    using namespace std;
    
    int r,c,sx,sy;
    int time[55][55],book[55][55],Next[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
    char tu[55][55];
    
    struct thm
    {
        int x;
        int y;
        int bs;
    }art[MAXN],flood[MAXN];
    
    void Flood(int x,int y)
    {
        int s=0,t=1,tx,ty;
        flood[1].x=x,flood[1].y=y;
        while(s<t)
        {
            s++;
            for(int i=0;i<4;i++)
            {
                tx=flood[s].x+Next[i][0];
                ty=flood[s].y+Next[i][1];
                if(tx<1 || ty<1 || tx>r || ty>c || tu[tx][ty]=='D' || tu[tx][ty]=='X' || time[tx][ty]!=INF)
                    continue;
                flood[++t].x=tx;
                flood[t].y=ty;
                time[tx][ty]=flood[t].bs=flood[s].bs+1;
            }
        }
    }
    
    int main()
    {
        scanf("%d%d",&r,&c);
        for(int i=1;i<=r;i++)
            for(int j=1;j<=c;j++)
                time[i][j]=INF;
        for(int i=1;i<=r;i++)
            scanf("%s",tu[i]+1);
        for(int i=1;i<=r;i++)
        {
            for(int j=1;j<=c;j++)
            {
                if(tu[i][j]=='S')
                    sx=i,sy=j;
                if(tu[i][j]=='*')
                    time[i][j]=0,Flood(i,j);
            }
        }
        int s=0,t=1,tx,ty;
        art[1].x=sx,art[1].y=sy;
        book[sx][sy]=1;
        while(s<t)
        {
            s++;
            if(tu[art[s].x][art[s].y]=='D')
                return printf("%d",art[s].bs),0;
            for(int i=0;i<4;i++)
            {
                tx=art[s].x+Next[i][0];
                ty=art[s].y+Next[i][1];
                if(tx<1 || ty<1 || tx>r || ty>c || art[s].bs+1>=time[tx][ty] || tu[tx][ty]=='X' || book[tx][ty]==1)
                    continue;
                art[++t].x=tx;
                art[t].y=ty;
                art[t].bs=art[s].bs+1;
                book[tx][ty]=1;
            }
        }
        printf("KAKTUS");
        return 0;
    }

    T2邦德I

    Description

    每个人都知道詹姆斯邦德,著名的007,但很少有人知道很多任务都不是他亲自完成的,而是由他的堂弟们吉米邦德完成(他有很多堂弟),詹姆斯已经厌倦了把一个个任务分配给一个个吉米,他向你求助。
    每个月,詹姆斯都会收到一些任务,根据他以前执行任务的经验,他计算出了每个吉米完成每个任务的成功率,要求每个任务必须分配给不同的人去完成,每个人只能完成一个任务。
    请你编写程序找到一个分配方案使得所有任务都成功完成的概率。

    Input

    输入第一行包含一个整数N,表示吉米邦德的数量以及任务的数量(正好相等,1<=N<=20)。
    接下来N行,每行包含N个0到100之间整数,第i行的第j个数Aij表示吉米邦德i完成任务j成功的概率为Aij%

    Output

    输出所有任务成功完成最大的概率,结果保留6位小数。

    Sample Input

    输入1:
    2 
    100 100 
    50 50 
    
    输入2:
    2 
    0 50 
    50 0 
    
    输入3:
    3 
    25 60 100 
    13 0 50 
    12 70 90 

    Sample Output

    输出1:
    50.000000
    
    输出2:
    25.000000
    
    输出3:
    9.100000

    考场思路/正解

    状压DP,虽然之前没打过,不过凭着之前对此概念的认识,考场成功想出了正解,不过却没有AC,原因是当我调代码到一半时,我突然想起yeqiao的昨晚训言,以及昨天AC一题还不如别人四题暴力的分高的惨痛事件(其实是处于对yeqiao来自心灵深处的恐惧),于是就用剩下的时间去打暴力,结果考试后,出来稍微改一下就AC了,无语。

    由于n<=20,所以我们可以用20位01串来记录第i个人是否有任务。因此我们可以设f[01串]来表示花费其中为1的位置上的人,处理前i(1的数量)的最优获益。方程式可想而知。

    Code

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    
    int n;
    int jl[1058576],g[1058576];
    double f[1058576];
    double gl[22][22];
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                scanf("%lf",&gl[i][j]),gl[i][j]/=100;
        jl[1]=1;f[1]=gl[1][1];
        for(int i=2;i<=n;i++)
            jl[i]=jl[i-1]*2,f[jl[i]]=gl[i][1];
        int sl1=n,sl2=0;
        for(int i=2;i<=n;i++)
        {
            
            for(int j=1;j<=n;j++)
                for(int k=1;k<=sl1;k++)
                    if(!((jl[k]>>(j-1))&1))
                        if(f[jl[k]|(1<<(j-1))]<f[jl[k]]*gl[j][i])
                            if(f[jl[k]|(1<<(j-1) )])
                                f[jl[k]|(1<<(j-1) )]=f[jl[k]]*gl[j][i];
                            else
                                g[++sl2]=jl[k]|(1<<(j-1) ),f[g[sl2]]=f[jl[k]]*gl[j][i];
            for(int j=1;j<=sl2;j++)
                jl[j]=g[j],g[j]=0;
            sl1=sl2,sl2=0;
        }
        printf("%.6lf",100*f[(1<<n)-1]);
        return 0;
    }

    T2餐桌

    Description

    你家刚买了一套新房,想邀请朋友回来庆祝,所以需要一个很大的举行餐桌,餐桌能容纳的人数等于餐桌的周长,你想买一个能容纳最多人的餐桌,餐桌的边必须跟房间的边平行。
    给你的房间的设计,计算最多能邀请的客人数。

    Input

    第一行包含两个整数R和C(1<=R,C<=2000),表示房子的长和宽。
    接下来R行每行S个字符(中间没有空格),“.”表示空白区域,“X”表示有障碍物,餐桌所占区域必须是空白的。

    Output

    输出最多能要求的客人数量。

    Sample Input

    输入1:
    2 2
    ..
    ..
    
    输入2:
    4 4 
    X.XX 
    X..X 
    ..X. 
    ..XX 
    
    输入3:
    3 3 
    X.X 
    .X. 
    X.X 

    Sample Output

    输出1:
    7
    
    输出2:
    9
    
    输出3:
    3

    Hint

    【数据规模】
    50%的数据R,C<=400
    70%的数据R,C<=1000
    100%的数据,R,C<=2000

    考场思路

    6重for,超级暴力,怎么暴力怎么来。

    正解

    单调栈,好像是这个东西,挺好理解的。

    Code

    #include<cstdio>
    #include<algorithm>
    #define INF 2e9
    using namespace std;
    
    int r,c,Min,zx,ans;
    int tu[2002][2002];
    char ch[2002];
    
    int main()
    {
        scanf("%d%d",&r,&c);
        for(int i=1;i<=r;i++)
        {
            scanf("%s",ch+1);
            for(int j=1;j<=c;j++)
                if(ch[j]=='.')
                    tu[i][j]=1;
        }
        for(int i=r-1;i>=1;i--)
            for(int j=1;j<=c;j++)
                if(tu[i+1][j] && tu[i][j])
                    tu[i][j]=tu[i+1][j]+1;
        for(int i=1;i<=r;i++)
        {
            for(int j=1;j<=c;j++)
            {
                if(!tu[i][j])    continue;
                Min=INF,zx=j;
                while(tu[i][zx])
                {
                    Min=min(Min,tu[i][zx]);
                    ans=max(ans,2*(Min+zx-j+1)-1);
                    zx++;
                }
            }
        }
        printf("%d",ans);
        return 0;
    }

    T4自行车比赛

    Description

    自行车赛在一个很大的地方举行,有N个镇,用1到N编号,镇与镇之间有M条单行道相连,起点设在镇1,终点设在镇2。
    问从起点到终点一共有多少种不同的路线。两条路线只要不使用完全相同的道路就被认为是不同的。

    Input

    第一行两个整数:N和M(1<=N<=10000,1<=M<=100000),表示镇的数量和道路的数量。
    接下来M行,每行包含两个不同的整数A和B,表示有一条从镇A到镇B的单行道。
    两个镇之间有可能不止一条路连接。

    Output

    输出不同路线的数量,如果答案超过9位,只需输出最后9位数字。如果有无穷多的路线,输出“inf”。

    Sample Input

    输入1:
    6 7 
    1 3 
    1 4 
    3 2 
    4 2 
    5 6 
    6 5 
    3 4 
    
    输入2:
    6 8 
    1 3 
    1 4 
    3 2 
    4 2 
    5 6 
    6 5 
    3 4 
    4 3 

    Sample Output

    输出1:
    3
    
    输出2:
    inf

    考场思路

    不会就暴力。。

    正解

    好像没有inf情况的数据诶,所以我们之间Tarjan缩点然后跑一遍拓扑排序就行了。

    Code

    #include<cstdio>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<iostream>
    #define Mod (long long)1e9
    #define LL long long
    #define Ud unsigned
    using namespace std;
    
    int n,m,cnt,Count,zx;
    int a[100010],b[100010],low[10010],dfn[10010],vis[10010],jl[10010],in[10010],kg;
    LL sl[10010];
    int stack[10010],top;
    Ud len1[10010],len2[10010];
    vector<int> rel1[10010];
    vector<int> rel2[10010];
    queue<int> q;
    
    void Trajan(int x)
    {
        int zx;
        dfn[x]=low[x]=++cnt;
        stack[++top]=x;vis[x]=1;
        for(Ud i=0;i<len1[x];i++)
        {
            if(!dfn[rel1[x][i]])
            {
                Trajan(rel1[x][i]);
                low[x]=min(low[x],low[rel1[x][i]]);        
            }
            else
                if(vis[rel1[x][i]])
                    low[x]=min(low[x],dfn[rel1[x][i]]);
        }
        if(dfn[x]==low[x])
        {
            Count++;
            do
            {
                zx=stack[top];
                jl[zx]=Count;
                vis[zx]=0;
                top--;
            }while(zx!=x);
        }
    }
    
    int main() 
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
            scanf("%d%d",&a[i],&b[i]),rel1[a[i]].push_back(b[i]);
        for(int i=1;i<=n;i++)
            len1[i]=rel1[i].size();
        for(int i=1;i<=n;i++)
            if(!dfn[i])
                Trajan(i);    
        for(int i=1;i<=m;i++)
        {
            if(jl[a[i]]==jl[b[i]])
                continue;
            rel2[jl[a[i]]].push_back(jl[b[i]]); 
            in[jl[b[i]]]++;
        }
        for(int i=1;i<=Count;i++)
            len2[i]=rel2[i].size();
        for(int i=1;i<=Count;i++)
            if(!in[i])
                q.push(i);
        sl[jl[1]]=1;
        while(!q.empty())
        {
            zx=q.front();q.pop();
            for(Ud i=0;i<len2[zx];i++)
            {
                in[rel2[zx][i]]--;
                sl[rel2[zx][i]]+=sl[zx];
                if(sl[rel2[zx][i]]>=Mod)
                    kg=1,sl[rel2[zx][i]]%=Mod;
                if(!in[rel2[zx][i]])
                    q.push(rel2[zx][i]); 
            }
        }
        
        if(kg)
            printf("%09lld",sl[jl[2]]);
        else
            printf("%lld",sl[jl[2]]);
        return 0;
    }

    总结

    发现自己还是存在很多知识盲区,得多补多刷题,不然怎么超过shy大佬

    I still have a long way to go. 

    距 NOIp2019 还剩 90 天      祭

     
  • 相关阅读:
    17. Letter Combinations of a Phone Number
    16. 3Sum Closest
    15. 3Sum
    14. Longest Common Prefix
    13. Roman to Integer
    12. Integer to Roman
    11. Container With Most Water
    10. Regular Expression Matching
    9. Palindrome Number
    8. String to Integer (atoi)
  • 原文地址:https://www.cnblogs.com/Thm-V/p/11333195.html
Copyright © 2011-2022 走看看