zoukankan      html  css  js  c++  java
  • SEU第一次训练练习题

    第一次不是以学为目的的做题,之前的题都是看了基本算法和模板代码以后去做的,所以这次非常有挑战性, 当然,这种难度还是轻松把我打败了

    A是hdu3088 WORM ,一道hash判重+BFS,一开始不会hash判重,更别说三进制hash了,那天正好看了lrj的书,里面一道八数码跟这题差不多,于是就硬写了两个钟头,到头来才发现memcmp和strcmp的原理不一样,用法也不一样,如果两个数组的开头a[0],b[0]是一样的,那么memcmp就会判断它是一样的,因为八数码问题每个数都不相同,所以lrj才那么用,算是被他坑了。后来因为没有懂得把r,b,g换成数字,也着实麻烦了一阵。

    //hash三进制判重+BFS 
    //输入rgb字符串转化成字符的123 
    //自己写的再看别人的代码以后才ac 
    #include<iostream>
    #include<cstring>
    #include<queue>
    #include<memory>
    using namespace std;
    
    const int maxst=100000;//字母的状态有3^10种排列 
    int t,len,h;
    bool vis[maxst];//hash表 
    int goal[3];
    char str[11];
    struct state{
        char ch[11];
        int step;
    
    };//队列节点 
    
    char change(char a,char b){
        if(a+b == '0'+'1') return '2';
        if(a+b == '0'+'2') return '1';
        if(a+b == '1'+'2') return '0';
    }
    
    int Hash(char* a)
    {
        int s=0,x;
        for(int i=0;i<len;i++)
            s=s*3+a[i]-'0';
        return s;
    }
    
    int bfs(){
    
        state st[maxst];
        queue<state>q;
        int step;
        state u;
        memset(vis,0,sizeof(vis));
        h=Hash(str);//习惯性的要先处理第一组数据
        if(h==goal[0]||h==goal[1]||h==goal[2])
               return 0;
        strcpy(u.ch,str);
        u.step=0;
        q.push(u);
        vis[h]=1;
        while(!q.empty()){
            u=q.front();
            u.step++;
            q.pop();
            h=Hash(u.ch);
            for(int i=0;i<len-1;i++)
            {
                if(u.ch[i]==u.ch[i+1])
                    continue;
                char x=u.ch[i],y=u.ch[i+1];//先保存下来 
                u.ch[i]=u.ch[i+1]=change(x,y);
                h=Hash(u.ch);
                if(h==goal[0]||h==goal[1]||h==goal[2])
                       return u.step;
                if(!vis[h])
                {
                    vis[h]=1;
                    q.push(u);
                }
                u.ch[i]=x;u.ch[i+1]=y;//还原 
            }
        }
        return -1;
    }
    
    int main (){
        char last[12];
        cin>>t;
        while(t--)
        {
            cin>>str;    
            getchar();
            len=strlen(str);
            for(int i=0;i<len;i++)
            {
                if(str[i]=='r')
                    str[i]='0';
                else if(str[i]=='b')
                    str[i]='1';
                else if(str[i]=='g')
                    str[i]='2';
            }
            str[len]='';
            for(int i=0;i<3;i++)
            {    
                for(int j=0;j<len;j++)
                    last[j]=i+'0';
                last[len]='';
                goal[i]=Hash(last);
            }    
            
            int ok=bfs();
            if(ok==-1)
                cout<<"No solution!
    ";
            else 
                cout<<ok<<endl;
        }
    }
    View Code

    B是hdu3091 Necklace,一道状态DP,本身比较简单,但是题目意思含糊,题目是说找出项链的方案,但貌似项链可以不用形成环。。。。所以这题我也无耻的看了别人的代码,其实最重要的原因是我根本没写过状态压缩T0T

    /* 
    找出n个珠子的某种组合方式,将这些组合方式放在一个二进制数里面 
    对每一个二进制状态S进行列举
    
    dp表示能够形成的条数,i表示链条的终点, 
    dp[S+{j}][j]=sigma dp[S][i] //i-j存在边,且i在S内 
    */
    
    //无向图
    #include<iostream> 
    #include<vector>
    #include<cstring>
    using namespace std;
    
    long long dp[(1<<18)+5][20];//开到19太大了 //注意<<时要用括号 //注意数据要用long long储存 
    int a,b,n,m;
    int maxS,S2,p;
    int S,i,j;
    
    int main(){
        
        while(cin>>n>>m)    
        {
            vector<int> v[20];//邻接表 
            memset(dp,0,sizeof(dp));
            for(i=0;i<m;i++)
            {
                cin>>a>>b;
                a--;b--;
                v[a].push_back(b);
                v[b].push_back(a);//注意减1!!! 
            }
            //S=1<<0代表空集,空集时显然不存在S之外某个点的邻接顶点在S中
            dp[1][0]=1;
            maxS=1<<n;
            for(S=1;S<maxS;S++)
            {
                for(i=0;i<n;i++)
                {
                    if( dp[S][i]==0 ) //表示S中没有i 
                        continue; 
                    for(j=0;j<v[i].size();j++)
                    {
                        p=v[i][j];
                        if(S&(1<<p))
                            continue;
                        S2=(S|(1<<p));
                        dp[S2][p]+=dp[S][i];
                    }
                }
            }
            
            long long ans=0;
            for(i=0;i<v[0].size();i++)
                ans+=dp[(1<<n)-1][v[0][i]];
            cout<<ans<<endl;
        }
        
        return 0;
    }
    View Code

    C是双向BFS,我到现在还是不会。。。

    D是hdu1254 推箱子,是一道比较明显的BFS+DFS或BFS+BFS,一开始写前一种不知道到底错在那里,后来把DFS换成BFS就AC了,这题写了一晚上还有早上两钟头。。。

    //显然当仅当箱子左右都是空地且不是边界时且人可到达时,人可以站在箱子左右推,既可往左推,也可往右推,并且箱子将被推到右边一格,步数加1,而此时人一定在箱子的左边 
    //遍历箱子的四个方向中可推的,然后推入队列。同时要带上人的位置
    
    //判断人能否到达一个位置
    //如果这个位置是边界或者墙,则不行
    //如果不是,则dfs 
    
    //mbd第一次写TLE,第二次什么都没改就0ms AC了 
    
    #include<iostream>
    #include<queue>
    #include<cstring>
    using namespace std;
    
    int t,n,m,endx,endy;
    const int dir[4][2]={{-1,0},{1,0},{0,1},{0,-1}};//左右上下 
    int map[8][8];
    bool vis[8][8][8][8];//用四维数组储存状态, 
    bool mark[8][8];
    
    bool can_stand(int x,int y){//处于状态u的时候的地图 
        if(x<=n&&x>0&&y>0&&y<=m&&map[x][y]!=1&&map[x][y]!=2)//先判断边界在判断map 注意map为3时也是可以走的 
            return 1;
        return 0;
    }
    
    struct state{
        int cx,cy;//此时人的位置 
        int bx,by;//此时箱子的位置
        int step;
        state(){} 
        state(int a,int b,int c,int d,int s){
            cx=a;cy=b;bx=c;by=d;step=s;
        }
    }; 
    
    struct node{
        int x,y;//差点多打了个变量step 
    };
    
    bool bfs2(state u,int x,int y){  //只需要判断能否到达 
    
        memset(mark,0,sizeof(mark));
        queue<node> q;
        node t,k;
        t.x=u.cx;
        t.y=u.cy;
        mark[t.x][t.y]=1;
        q.push(t);
        while(!q.empty()){
            k=q.front();
            q.pop();
            if(k.x==x&&k.y==y)
                return 1;
            for(int i=0;i<4;i++)
            {
                int nx=k.x+dir[i][0],ny=k.y+dir[i][1];
                if(can_stand(nx,ny)&&!mark[nx][ny])
                {
                    t.x=nx;t.y=ny;
                    q.push(t);
                    mark[nx][ny]=1;
                }
            }
        }
        return 0;
    }
    
    int bfs(){//走到一个位置时,要记得改变map的值 
        
        queue<state> q;
        state u;
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=m;i++){
            for(int j=1;j<=n;j++)
            {
                if(map[j][i]==2)
                {    u.bx=j;u.by=i;    }
                if(map[j][i]==3)
                {    endx=j;endy=i;    }
                if(map[j][i]==4)
                {    u.cx=j;u.cy=i;    }
            }
        }
        u.step=0;
        q.push(u);
        
        int nx,ny,rx,ry;
        while(!q.empty()){
            
            u=q.front();
            q.pop();
            if(u.bx==endx&&u.by==endy)
                return u.step;
                
            vis[u.cx][u.cy][u.bx][u.by]=1;
            map[u.bx][u.by]=2;//在此之前地图中没有箱子 
            for(int i=0;i<4;i++) 
            {
                nx=u.bx+dir[i][0];ny=u.by+dir[i][1];//推箱子的时候人应该站的位置 
                rx=u.bx-dir[i][0];ry=u.by-dir[i][1];//箱子要被推到的位置 
                if(can_stand(nx,ny)&&can_stand(rx,ry)&&!vis[nx][ny][rx][ry])
                    if(bfs2(u,nx,ny))//u这个状态的人能不能到达(nx,ny) 
                    {
                        state v(u.bx,u.by,rx,ry,u.step+1);
                        q.push(v);
                        vis[nx][ny][rx][ry]=1;
                    }
            }
            //判断箱子周围可到达的格子之后
            map[u.bx][u.by]=0;
        }
        return -1;
    }
    
    int main(){
        cin>>t;
        while(t--)
        {
            memset(map,0,sizeof(map));
            cin>>m>>n;//m行n列 map[j][i] j列i行 
            for(int i=1;i<=m;i++)
                for(int j=1;j<=n;j++)
                    cin>>map[j][i];
            cout<<bfs()<<endl;
        }
        return 0;
    }
    View Code

    E是hdu1284 钱币兑换问题,一道数学水题,没啥意思

    //决定了y与z之后,x就被唯一决定了 
    #include<iostream>
    using namespace std;
    
    int n,sum;
    int main(){
        
        while(cin>>n)
        {
            sum=0;
            for(int i=0;i<=n/3;i++)
                sum+=(n-3*i)/2+1;
            cout<<sum<<endl;
        }
        return 0;
    } 
    View Code

    F是hdu1285 确定比赛名次,一道拓扑排序,本来很简单,但是我之前没写过拓扑,不过看了思路以后就一次AC了

    //hdu1285 方法想不到 
    
    #include <iostream>
    #include <cstring>
    #include <vector>
    using namespace std;
    
    const int maxn=505;
    
    int n, m;
    int d[maxn]; 
    bool vis[maxn];
    
    int main() {
        int i, j;
        while (cin>>n>>m) {
            
            vector<int>v[maxn];
            memset(d,0,sizeof(d));
            for (int i=1;i<=m;i++) {
                int a, b;
                cin>>a>>b;
                d[b]++;
                v[a].push_back(b);
            }
            
            memset(vis,0,sizeof(vis));
            int c=0;//已经输出了几个 
            for(int i=1;i<=n;i++)
            {
                for(int j=1;j<=n;j++)//因为要按字典序输出,所以从前往后找点 
                    if(!vis[j]&&!d[j])
                    {
                        vis[j]=1;
                        for(int k=0;k<v[j].size();k++)
                             d[v[j][k]]--;
                             
                         c++;
                        if(c==n)
                            cout<<j<<endl;
                        else
                            cout<<j<<" ";    
                         break;
                    }
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    配置WebLogic的详细步骤
    安装WebLogic的详细步骤
    syswrite 函数
    利用perl 改写awk统计
    第一章 输入和输出基础
    CIO必看:跨国集团采购部报表系统的建设经验分享
    价值5000元的web报表分享
    价值5000元的web报表分享
    分页语句 where 条件列和Order by 列 引导列的问题
    Java中final修饰参数的作用
  • 原文地址:https://www.cnblogs.com/neverchanje/p/3583296.html
Copyright © 2011-2022 走看看