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
原文地址:https://www.cnblogs.com/neverchanje/p/3583296.html