2018湖南多校第二场20180407训练日志

solve 4  (A  B  E  H)

rank  15/32

比赛链接:http://acm.csu.edu.cn:22080/cpcsys/contest/problemset?cid=1023

A题Sim Card:(通过)

签到题,且没什么可写的。

B题Bank Card Verifier:(通过)

签到题,跟着题目要求写就行了。

C题Border Wall

D题World Cup Draw

E题Barareh on Fire:(通过)

题意:火焰每k秒蔓延一次,能否从s点最快走到t点。

思路:

直接搜索,主要是每k秒更新一下新地图便可。

可以直接预处理新地图,要省空间的话可以中途更新。

其余的就是普通的bfs过程了。

搜索题中比较考验码力的题,代码如下:

#include <cstdio>
#include <algorithm>
#include <queue>
#include <iostream>
using namespace std;
struct node
{
    int x,y;
    int step;
    node(int x=0,int y=0,int step=0):x(x),y(y),step(step) {}
};
int mp[110][110][110],n,m,k;
char ch[110];
int bfs(int x,int y,int sx,int sy)
{
    int vis[110][110]= {};
    queue<node> q;
    while(!q.empty()) q.pop();
    q.push(node(x,y,0));
    vis[x][y]=1;
    while(!q.empty())
    {
        node nod = q.front();
        if(nod.x==sx&&nod.y==sy) return nod.step;
        q.pop();
        if(nod.x>0&&!vis[nod.x-1][nod.y]&&mp[(nod.step+1)/k][nod.x-1][nod.y])
        {
            vis[nod.x-1][nod.y]=1;
            q.push(node(nod.x-1,nod.y,nod.step+1));
        }
        if(nod.x<n-1&&!vis[nod.x+1][nod.y]&&mp[(nod.step+1)/k][nod.x+1][nod.y])
        {
            vis[nod.x+1][nod.y]=1;
            q.push(node(nod.x+1,nod.y,nod.step+1));
        }
        if(nod.y>0&&!vis[nod.x][nod.y-1]&&mp[(nod.step+1)/k][nod.x][nod.y-1])
        {
            vis[nod.x][nod.y-1]=1;
            q.push(node(nod.x,nod.y-1,nod.step+1));
        }
        if(nod.y<m-1&&!vis[nod.x][nod.y+1]&&mp[(nod.step+1)/k][nod.x][nod.y+1])
        {
            vis[nod.x][nod.y+1]=1;
            q.push(node(nod.x,nod.y+1,nod.step+1));
        }
    }
    return -1;
}
int main()
{
    int flag=1;
    while(scanf("%d %d %d",&n,&m,&k))
    {
        if(!n&&!m&&!k) break;
        int x,y,sx,sy;
        for(int i=0; i<n; i++)
        {
            scanf("%s",ch);
            for(int j=0; j<m; j++)
            {

                if(ch[j]=='s')
                {
                    mp[0][i][j]=1;
                    x=i;
                    y=j;
                }
                else if(ch[j]=='t')
                {
                    mp[0][i][j]=1;
                    sx=i;
                    sy=j;
                }
                else if(ch[j]=='f')
                {
                    mp[0][i][j]=0;
                }
                else if(ch[j]=='-')
                {
                    mp[0][i][j]=1;
                }
            }
        }
        for(int p=1; p<max(n,m); p++)
        {
            for(int i=0; i<n; i++)
            {
                for(int j=0;j<m;j++)
                {
                    mp[p][i][j]=1;
                    if(i>0&&j>0&&!mp[p-1][i-1][j-1]) mp[p][i][j]=0;
                    if(i>0&&!mp[p-1][i-1][j]) mp[p][i][j]=0;
                    if(j>0&&!mp[p-1][i][j-1]) mp[p][i][j]=0;
                    if(i>0&&j<m-1&&!mp[p-1][i-1][j+1]) mp[p][i][j]=0;
                    if(i<n-1&&j>0&&!mp[p-1][i+1][j-1]) mp[p][i][j]=0;
                    if(i<n-1&&!mp[p-1][i+1][j]) mp[p][i][j]=0;
                    if(j<m-1&&!mp[p-1][i][j+1]) mp[p][i][j]=0;
                    if(i<n-1&&j<m-1&&!mp[p-1][i+1][j+1]) mp[p][i][j]=0;
                }
            }
        }
        int ans=bfs(x,y,sx,sy);
        if(ans==-1) printf("Impossible\n");
        else printf("%d\n",ans);
    }
    return 0;
}

/**********************************************************************
    Problem: 1263
    User: multi2018team024
    Language: C++
    Result: AC
    Time:164 ms
    Memory:7228 kb
**********************************************************************/

F题Homotopic Paths

G题New Country Division

H题Column Addition:(通过)

题意:给长度为n的加法计算式a+b=c,问最少删除多少列使得式子正确。

思路:

<错误的贪心策略(虽然不知道哪里错了)>

对于第pos位,如果(a[pos] + b[pos])%10==c[pos] 或者 (a[pos] + b[pos] +1)%10==c[pos] 

pos位有可能留下,其余的一定要删掉(易证)。

那么把必须删掉的提前处理完,从而达到剪枝的目的。

<但是其实不需要贪心处理就可以ac这题>

<一个正确的策略>

由于数字最长只有1000位,我们不妨设dp[pos],表示第pos位合法时,能够得到的最长的合法序列有多长。

(1)对于所有的pos:

if((a[pos]+b[pos])%10==c[pos]) dp[pos]=1;

(2)对于第pos位,能否跟第pos+x位连接起来的条件是:

int jinwei=(dp[pos+x])&&(a[pos+x]+b[pos+x]>c[pos+x]);
if((a[pos]+b[pos]+jinwei)%10==c[pos]) dp[pos]=max(dp[pos],dp[pos+x]+1);

注意这里的变量 jinwei ,满足进位的条件当且仅当第pos+x位的a + b > c并且dp[pos+x]有值(如5+8=1这种式子是非法的,所以可以直接忽略掉,前面的贪心策略有处理掉这种非法式子)。

(3)如果第pos位本位不进位,那么这一位可以作为新式子的最高位,所以答案可以这样更新:

if((a[i]+b[i]<=c[i]))ans=min(ans,n-dp[i]);

最后贴上dzc巨巨的ac代码:

#include <cstdio>
#include <algorithm>
#include <queue>
#include <iostream>
#include <cstring>
using namespace std;
int n,ans=0;
string s1,s2,s3;
int a[1010],b[1010],c[1010],dp[1010];
int main()
{
    while(scanf("%d",&n)!=EOF&&n){
        ans=n;
        cin>>s1>>s2>>s3;
        for(int i=0;i<n;i++)
        {
            a[i]=s1[i]-'0';
            b[i]=s2[i]-'0';
            c[i]=s3[i]-'0';
        }
        memset(dp,0,sizeof(dp));
        for(int i=n-1;i>=0;i--)
        {
            if((a[i]+b[i])%10==c[i]) dp[i]=1;
            for(int j=i+1;j<n;j++)
            {
                int jinwei=(dp[j])&&(a[j]+b[j]>c[j]);
                if((a[i]+b[i]+jinwei)%10==c[i]) dp[i]=max(dp[i],dp[j]+1);
            }
        }
        for(int i=0;i<n;i++)
        {
            if((a[i]+b[i]<=c[i]))ans=min(ans,n-dp[i]);
        }
        printf("%d\n",ans);
    }
    return 0;
}

/**********************************************************************
    Problem: 1266
    User: multi2018team024
    Language: C++
    Result: AC
    Time:160 ms
    Memory:2040 kb
**********************************************************************/

I题Cafe Bazaar

J题Getting Back Home

K题Mars

原文地址:https://www.cnblogs.com/dowhile0/p/8734240.html