Ecust2019算法练习3-DFS

Ecust2019算法练习3-DFS

题目如下,选自hdu

在这里插入图片描述
这期WA惨不忍睹,有个题交了11发
在这里插入图片描述

下面开始附上题解,代码在最后,第二次做这种活,欢迎批评指正。

部分题解略
(明天补)

1001
  • 01连连看 hdu1175
  • 题意:n(<=1000)*m(<1000)地图,摆放着棋子,0表示空地,其余为棋子类型。现有q(q<50)次查询,问棋子能否消去(类型相同,可经过内部空地转折不超过两次)。是输出YES
  • 输入:n,m随后跟着n*m不同类型的空地与棋子。然后q次查询,每次查询包括x1,x2,y1,y2;输出:YES/NO
  • 题解:DFS。你的思路要清晰:剪枝+递归基+深度遍历。Void DFS(int x, int y, int dic,int turn),要记录的有当前行走位置(x,y),方向(dic),当前转弯次数(turn)。If(turn>2) return; if(turn==2 && (ey-y)!=0&&(ex-x)!=0) return; if(turn<=2&&(x==ex)&&(y==ey)) cout<<YES; return; 否则开始深度遍历。For(int i = 0; i < 4; i++){ xx = x+dic[i]; yy = y+dic[i]; if(!vis[xx][yy]&&!out(xx,yy)){vis[xx][yy]=true; if(dic==i) DFS(xx,yy,I,turn); else DFS(xx,yy,i,turn+1); vis[xx][yy]=false; } }
  • 技巧:这题的剪枝函数很漂亮:当转弯次数为2,但是当前位置和终点还不在一条直线上,说明到达无望,剪枝。因为开始时是没有方向的,所以特判一下,进第一个分支。
  • 复杂度:DFS遍历完全四叉树O(qnm)
1002
  • 02诡异的楼梯 hdu1180
  • 题意:迷宫题。特殊地形,楼梯,每移动一次由’|’变为’—’,变为限制上下通过。已知,从楼梯的一侧走到另一侧也只要一步。求最短步数。
  • 输入:m,n,随后跟着m*n维迷宫。输出:最短步数。
  • 题解:BFS最短步长。这题难点是直接需要根据步长判定这个方向能不能走,不能走的话,要等1s加入到队列中。再走即可。注意两种楼梯形态要分别讨论。
  • 技巧: 看网上的题解说要进行优化,否则会MLE和TLE。但是我实际测了一下,去掉用于优化的vis数组相关代码也可以0msAC。优化如下,感兴趣朋友可以参考一下。如果在楼梯旁却不符合当前楼梯的移动条件,使用vis[]数组记录等待过没有。如果已经等待过,就不加入队列中,防止爆内存,因为如果等待两次三次的节点加入,是没意义的。如果没有等待过,就加入即可。
  • 复杂度:O(mn)
1003
  1. 03最大连续子序列
  2. 题意:求K(<10000)个数的最大连续子序列和。
  3. 输入:K,随后跟着K个数。输出:满足条件子序列第一个和最后一个元素。(不唯一输出最小的那个)
  4. 题解:用dp解,dp[i]为以i为末尾的最大连续子序列元素和 。状态转移方程:dp[i] = max(a[i],dp[i-1]+a[i]);然后子序列第一个元素,得到了和,根据和逆序减一下,下标就可以得到了。
  5. 技巧:动态规划线性问题。由于找最大的和,初始化时最小的Min,-0x3ffffff。当然0也行,这题规定了负数不考虑,直接输出3个0。
  6. 复杂度:O(n^2)
1004
  • 小希的数表 hdu1270
  • 题意:N(3<=N<=100)个数,每个数不超过5000。已知它们两两相加的和N*(N-1)/2个,求这N个数各是多少。这N个数也是按照和的顺序排列的。
  • 输入:N,随后跟着N*(N-1)/2个数和。输出:N个数
  • 题解:DFS。这题还是有技巧的,技巧在于,DFS()深入的层数并不应该是a[i]数表的长度,而应该是我们要得到的结果是这N个数,因此我们用DFS(int x)和ans[x]表示。第一步,我们可以利用最小和的去枚举最小数,开始DFS。对于当前位置ans[x],要遍历所有数表a[i],取a[i]中元素,枚举已经有的在ans[]里的加数x,认为a[i]是由x+y组成的,于是我们作差得到新加数v (a[i]-ans[j]),并检验加数v加入ans[]得到的新数表是否合法,更新每个和数出现的次数,只要新加数产生的新和满足当前状态a[i]vis[i]分布即可,若可行进行下一层DFS。
  • 技巧:为了避免重复数据,首先需要进行整理。用tot变量记录去重个数,if(a[i]!=a[tot]) a[++tot]=a[i]; vis[tot]=1; else vis[tot]++; 则对于n*(n-1)/2的和,第i种为a[i],重复次数为ans[i]。感谢李震提供标程和题解。这个新加数的新和满足当前状态的程序段也很有技巧。int pos = lower_bound(a+1,a+1+tot,tmp)-a;然后vis[pos–],如果有负数出现,证明不符合分布。注意回溯时,要还原vis[]。李震大佬的代码十分优雅。
  • 复杂度:O(logN*NN^3)
1005
  • 变形课 hdu1181
  • 题意:给出多个单词的首末字母,问能否建立从B到M的有向连通图。
  • 输入:单词组;输出:Yes.
  • 题解:这题没给复杂度,有向连通图先直接遍历试试。用char[][]数组存储起点终点,三层循环遍历即可。
  • 技巧:e[i][j]|=e[i][k]&e[k][j]。这样从0-26循环即可得到全部连通图
  • 复杂度:O(N),三层循环是26^3常数级别。
1006
  • Substrings hdu1238
  • 题意:找n(n<100)个字符串(串长<100)组的公有或反转公有的最长子串长度,如rose,orchid,or为共有串。
  • 输入:T,n,随后是n个串。输出:最长子串长度
  • 题解:枚举搞一下。想想复杂度,对串长L进行枚举,然后以串长L遍历第一个串,看它或者反转串是否在n-1个串出现。出现即可行。
  • 技巧:二分枚举L可以降低复杂度。
  • 复杂度:O((n2)(L3)) 串长L反转L比较L
1007
  • What are you talking about hdu1075
  • 题意:给定多句火星文(一句<3000字母,每个单词最多10个字母)和键值对字典。问将字典内元素替换后的句子是。
  • 输入:字典与多句话。输出多句话。
  • 题解:map<string,string>,将一句话拆分成单词。对每个单词扫描map替换,这个方法的复杂度是分割一遍O(n),对每个单词进行处理O(3000k)。复杂度估计一下可能大于1e7。但是先交一发再说。交了两发发现复杂度是够的,但是有bug。发现前后缀的字典串没处理(比如你的句子是th,字典是t,这种情况不翻译)。
  • 技巧:交了6发WA过了。考虑前缀,注意在最后没有后缀空格的情况下要输出剩余的串。
  • 复杂度:每个字扫一遍。O(n),每个单词都查字典O(logk),m句话。因此O(mnlogk)
1008
  • Prime Ring Problem hdu1016
  • 题意:素数环。环的相邻元素和是素数组成。
  • 输入:环的位置n;输出:素数环的排列
  • 题解:DFS。对于每个位置递归。DFS(int t){if(t==n+1 && a[n]+a[1]==prime) output(); else{for(int j = 1; j <= n; j++) if(!vis(j)) a[t]=j; vis[j]=1; DFS(t+1); vis[j]=0}}
  • 技巧:素数筛。初始认为全是素数,然后筛掉不是素数的。for(int i=2;i<=n;i++){if(isprime[i])for(int j=i+i;j<=n;j+=i)isprime[j]=0;}
  • 复杂度:O(nn)
1009
  • 09 Ignatius and the Princess I hdu1026
  • 题意:王子(0,0)救公主(n-1,m-1)(2<n,m<100)。.为空地,数字为延时怪物,要停留num秒,X为陷阱。求最短用时。如果无法到达,则输出特定语句。
  • 输入:n,m随后跟着n,m个迷宫。输出,最短用时/特定语句。
  • 题解:BFS+优先队列+回溯。与DFS不同的是,BFS是通过构建node结构体{记录(x,y),step值}。首先第一个node入队,当队列非空,优先级队列队首top(非front)出队,不越界就访问。然后遍历4个方向。空地step+1,非空地step+hp+1。If(step)非0,开始回溯输出。
  • 技巧: 回溯法,由于本题输出复杂,因此写成迭代版本用way[i]存储,way开错了大小导致我交了3发WA。将cx,cy赋值给N,M。然后way[i].(x,y)=(cx,cy),如果是怪兽,要一直根据hp倒推。最后根据dic[x][y]赋值新cx,cy.
  • 复杂度:O(nm)
1010
  • Buy the Ticket hdu1133
  • 题意:持50元m人100元n(m,n<=100)人买票。初始售票处没钱,问有多少种排队方式,让售票处有的找零完成售票。
  • 输入:m,n,输出:找钱方式
  • 题解:这题竟然用dp做,符合重复子问题特性,属于区间问题。构造一个dp[i][j]为m个50,n个100的排队数。如果有一个为0,输出m!或n!。dp[i][j]=dp[i][j-1](m-i+1)+ dp[i-1][j](n-j+1))。意思为如果第i号位置选50,还剩(m-i+1)张50,故有这些选择;同理100也这样选。注意for循环并不是双层i=1tom,j=1ton循环,而是j=1tomin(i,n)。j不能选取多于i的100数目,无法找零。
  • 技巧:这题数字很大。我找了个模板,大数加法与输出。即可得到答案
  • 复杂度:O(mn)
1011
  1. 11 Reverse Text
  2. 题意:一n个节点的树,树的每个节点上可能有一些bug。你有m组军队,每组军队可以处理一个节点的20个bug,处理掉一个节点的所有bug会有一定收益,你从1号节点出发,可以分兵,进入下一个节点之前必须解决掉当前节点的bug。求你能获得的最多收益。
  3. 输入:n个结点,m个军队。随后跟着n个结点的虫子数和大脑概率。再跟着n-1个结点的树分支的情况。输出:最大可能找到大脑的路径。
  4. 题解:树形动态规划,转移类似背包。这题参考了李震大佬的题解。f[i][j]表示在以i为根的子树上,分配j组兵能获得的最大收益。f[x][j+k]=max(j+k≤m){f[x][j+k],f[x][j]+f[y][k]}其中,x为当前节点,y为x的子节点。最终答案为f[1][m]。
  5. 技巧: 这个题我自己不太理解,回去补B站视频。
  6. 复杂度:O(nm^2)
1012
  • 12 Reverse Text
  • 题意:给出一个字符串,输出反转串。
  • 输入:n,随后跟着n个串。
  • 题解:15行就过了。
  • 技巧:gets();读一行
  • 复杂度:O(n)
1013
  • 13 Gizilch hdu1416
  • 题意:在一个比赛中,有1号到100号葡萄给两个选手争抢,选手得分为抢到的葡萄编号之积。给出两个选手的得分,保证得分不同,低分选手会质疑高分选手说谎,假定低分选手不说谎(The player with the lower score is presumed to have told the truth)。你要判断高分选手是否说谎,如果说谎,输出低分选手分数,否则输出高分选手分数。
  • 输入:n1,n2。输出:指定分数。
  • 题解:DFS。对于每个数,有三种状态,都没拿,A拿了或者B拿了。然后看是否能达到所给的n1,n2数。如果能达到,必没有公共因子。感谢李震的题解。
  • 技巧:这里搜索了两次。由于题设不太严谨,小数可能撒谎,那么一定要看小数能否由相应的数组成,即不是大于100质数。然后再看小数和大数是否含有公因子,如果不含有公因子。那么一定能达到搜索的叶结点,返回大数胜利,否则大数失败。总结,小数胜利有一个条件就是在自身不是大于100的质数下质疑成功。 故满足要求
  • 复杂度:O(3100)
1014
  1. 14 A Strange Lift hdu1548
  2. 题意:电梯每层楼都有可以到的楼层增量减量,问最小几步可以到达指定的楼层。
  3. 输入:n,a,b,随后跟着n个楼层变量ki。
  4. 题解:BFS最短步长。两个选择,搜索就完事了。上楼就加对应的楼层,判断是否越界。不越界就加到队列里。
  5. 技巧: 这题有个优雅的写法。开for(int i = -1; i<=1; i++)循环,这样上下楼就是对应的1和-1的乘法。需要vis[]数组,不能重复。
  6. 复杂度:O(n)
1015
  1. 15 Square hdu1511
  2. 题意:给定T组数据。M(4<M<20)个筷子的长度,问筷子能否拼成正方形
  3. 输入:T,M,随后跟着M个长度;输出:Yes,No
  4. 题解:DFS。这题可以转化成,筷子能否拼成4个,总长度/4的组合,记作A,因此在搜索前我们可以先将筷子排序,使之从大到小是有序的。在搜索时,我们需要记录当前已经拼成的组合数x,当x==4搜索结束。Sum为当前的和,如果sum==A,则x++,可以进入下一层搜索。当然也要记录,筷子长度数组a[i]的下表p。那么搜索的分支如下,对于[p+1,N]区域的筷子,如果长度小于A,就取。否则不取。
  5. 技巧: 在搜索前将筷子排序是一个常见的技巧,可以加快搜索的速度。因为不取的条件是筷子长度较大,因此从大到小取比较优雅。
  6. 复杂度:因为叶节点到4停止搜索,时间复杂度为O(3^m)

代码合集,仅供参考!!!

//1001
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1003;
const int ad_[4]={1,-1,0,0},ws_[4]={0,0,1,-1};//左右下上
int G[maxn][maxn];
bool vis[maxn][maxn]={0}; //棋子和访问过的数组
int n,m,q;
int sx,sy,ex,ey; //查询点
bool flag; //是否找到解
bool out(int x,int y){
    return x<=0 || y<=0 || x>n || y>m || vis[x][y];
}
void dfs(int x,int y,int dic,int turn){
    if(turn>2) return; //cut
    if(turn==2&&(x-ex)!=0&&(y-ey)!=0) return; //cut
    if(x==ex&&y==ey&&turn<=2){//命中
        flag = true;
        return;
    }
    for(int i = 0; i < 4; i++){
        int xx = x + ad_[i];
        int yy = y + ws_[i];
        if(out(xx,yy)) continue;
        if(!G[xx][yy] || xx==ex&&yy==ey){//空地或者命中(命中一定要考虑,否则WA)
            vis[xx][yy] = 1; //访问了
            if(dic == -1 || dic == i) dfs(xx,yy,i,turn);
            else dfs(xx,yy,i,turn+1);
            vis[xx][yy] = 0;
        } 
    }
}

int main(){
    freopen("in.txt","r",stdin);
    while(cin>>n>>m,n){
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m; j++){
                scanf("%d", &G[i][j]);
            }
        }
        cin>>q;
        while(q--){
            flag = 0;
            cin>>sx>>sy>>ex>>ey;
            if(G[sx][sy]==G[ex][ey]&&G[sx][sy]){//相同棋子
                dfs(sx,sy,-1,0);
            }
            if(flag) cout<<"YES"<<endl;
            else cout<<"NO"<<endl;
        }
    }
    return 0;
}
//1002
//优化过的代码,去掉vis数组相关代码也可以0msAC
#include <iostream>
#include <queue>
using namespace std;
int n,m,ans,dic[4][2]={{1,0},{0,1},{-1,0},{0,-1}},visit[22][22],vis[22][22];  
//dic是方向,visit是记录访问过的点
//vis记录楼梯面前是否已经等待,因为每个楼梯只有两种状态,所以我要等的话等一次就够了
int sx,sy,ex,ey;  //起点与终点的坐标
char G[22][22];  
struct node{
    int x,y,step;
    node() {}
    node(int _x,int _y,int _step):x(_x),y(_y),step(_step) {}
}Node;
bool out(int x,int y){
    if(x<0 || x>n || y<0 || y>m || (G[x][y]=='*') || visit[x][y]==1) return 1;
    return 0;
}
void bfs(){
    queue<node> q;
    int xx,yy,X,Y,step;
    q.push(node(sx,sy,0));visit[sx][sy]=1;
    while(!q.empty()){
        Node=q.front();q.pop();
        X=Node.x;Y=Node.y;step=Node.step;  //X,Y,step记录下当前的坐标和步数
        if(G[X][Y]=='T'){ans=step;return;} 
        for(int i=0;i<4;i++){
            xx=X+dic[i][0];
            yy=Y+dic[i][1];
            if(out(xx,yy)) continue;
            if(G[xx][yy]=='|'){  //如果是纵向的楼梯
                xx+=dic[i][0];yy+=dic[i][1];
                if(out(xx,yy)) continue; 
                //楼梯是每分钟变一次,但是只有两种状态,就是纵向和横向,所以根据步数可以计算当前楼梯的状态
                //if里面就是判断是否可以走,不然就是等待,当然要看先前是不是已经在这里等待过一次了,不然就会超时超内存的
                if(i%2==0&&step%2==0||i%2==1&&step%2==1){visit[xx][yy]=1,q.push(node(xx,yy,step+1));}
                else if(vis[xx][yy]==0){vis[xx][yy]=1,q.push(node(X,Y,step+1));}
            }else if(G[xx][yy]=='-'){  //如果是横向的楼梯            
                xx+=dic[i][0];yy+=dic[i][1];
                if(out(xx,yy)) continue; 
                if(i%2==0&&step%2==1||i%2==1&&step%2==0){visit[xx][yy]=1,q.push(node(xx,yy,step+1));}
                else if(vis[xx][yy]==0){vis[xx][yy]=1,q.push(node(X,Y,step+1));}
            }else{visit[xx][yy]=1,q.push(node(xx,yy,step+1));}  //(.和T)就正常走
        }
    }
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif
    while(cin>>n>>m){
        for(int i=0;i<n;i++)
        for(int j=0;j<m;j++){
            cin>>G[i][j];
            visit[i][j]=vis[i][j]=0;
            if(G[i][j]=='S')sx=i,sy=j;  
            if(G[i][j]=='T')ex=i,ey=j;  
        }
        ans=0;
        bfs();
        cout<<ans<<endl;
    }
    return 0;
}
//1003
/* 题意:求K(<10000)个数的最大连续子序列和。
并输出子序列第一个和最后一个元素。(不唯一输出最小的那个)
*/
/* 题解:用dp解,dp[i]为以i为末尾的最大连续子序列元素和
*/
#include <bits/stdc++.h>
#define MIN -0x3fffffff
using namespace std;
int a[10010],dp[10010];
int main(){
    freopen("in.txt","r",stdin);
    int n;
    while(cin>>n,n){
        bool isMinus = 1;
        int re = 0,j = 0,k = 0;//k为左边界,j为右边界
        memset(dp,0,sizeof(dp));
        for(int i = 1; i <= n; i++){
            scanf("%d",&a[i]);
            if(a[i]>=0) isMinus = 0; 
        }
        if(isMinus){
            cout<<"0 "<<a[1]<<" "<<a[n]<<endl;
            continue;
        }
        for(int i = 1; i <= n; i++){; 
            dp[i] = max(a[i],dp[i-1]+a[i]);
        }
        for(int i = 1; i <= n; i++){
            if(dp[i] > re){
                re = dp[i];
                j = i;
            }
        }
        int remain = re,index = j;
        while(index--){//j下表倒推一下即可
            remain -= a[index+1];
            if(!remain) break;
        }
        cout<<re<<" "<<a[index+1]<<" "<<a[j]<<endl;
    }
    
}
//1004(感谢大佬代码)
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 5010;
int n,m,tot;
int a[maxn],ans[maxn],vis[maxn];
int ok;
void dfs(int x){
    if(ok) return;
    if(x==n+1){
        sort(ans+1,ans+1+n);
        for(int i = 1; i < n; i++) printf("%d ",ans[i]);
        printf("%d\n",ans[n]);
        ok = 1;return;
    }
    for(int i = 1; i <= tot; i++){//遍历和数组(4 5 7 10 12 13)
        if(vis[i]){//访问到了a[i]的重复vis[i]次的数
            for(int j = 1; j < x; j++){//遍历已有加数集合的前几个加数u(1 3 4)
                int v = a[i] - ans[j];//新加数v(3 4 5..设i=2,此时为4)
                //判断新加数多个y是否合法。只要新的和满足a[i]vis[i]分布即可
                if(v<=0) continue;
                bool flag = 1;
                for(int k = 1; k <x; k++){
                    int tmp = v+ans[k];//新和(v4+u2=6)
                    if(tmp>a[tot]){ flag = 0; break;}//加和太大,舍去
                }
                if(!flag) continue;
                for(int k = 1; k <x; k++){
                    int tmp = v+ans[k];//新和
                    int pos = lower_bound(a+1,a+1+tot,tmp)-a;
                    vis[pos]--;//为什么不是i--?i控制的是遍历进度,而当和越界时要剪枝,所以要求出越界时的pos
                    if(vis[pos]<0) flag = 0;
                }
                ans[x]=v;
                if(flag) dfs(x+1);
                for(int k=1;k<x;k++){
                    int tmp=v+ans[k];
                    int pos=lower_bound(a+1,a+1+tot,tmp)-a;
                    vis[pos]++;
                }
            }
            break;
        }
    }
}

int main(){
    freopen("in.txt","r",stdin);
    while(cin>>n,n){
        m = n*(n-1)/2,tot=0;
        for(int i = 1; i <= m; i++){
            scanf("%d",&a[i]);
            //将a[i]去重得到a[tot],并记录重复元素重复个数vis[tot]
            if(a[i]!=a[tot]){
                a[++tot]=a[i];vis[tot]=1;
            }
            else vis[tot]++;
        }
        ok=0;
        //dfs:第一个数从1到<最小和
        for(int i = 1; i < a[i]; i++){
            ans[1]=i;
            dfs(2);//从第二个元素开始
            if(ok) break;
        }
    }
    return 0;
}
//1005(感谢李震大佬的elegant code)
#include<cstdio>
#include<cstring>
const int maxn = 100;
bool e[26][26]; //存是否存在边
char s[maxn]; //存字符串
int main(){
    freopen("in.txt","r",stdin);
    while(scanf("%s",s)!=EOF){
        int lens;
        memset(e,0,sizeof(e));
        while(1){
            lens = strlen(s);
            if(s[0]=='0'&&lens==1) break;
            e[s[0]-'a'][s[lens-1]-'a']=1;   
            scanf("%s",s);
        }
        bool flag=0;
        for(int k = 0; k <26; k++){
            for(int i = 0; i <26; i++){
                for(int j = 0; j <26; j++){
                    e[i][j]|=e[i][k]&e[k][j];
                }
            }
        }
        if(e['b'-'a']['m'-'a']) printf("Yes.\n");
        else printf("No.\n");
    }
    return 0;
}

//1006(感谢李震大佬的代码)
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
char s[100][100];
int N,L;
int len[100];
inline bool match(int a,int la,int ra,int b,int lb,int rb){
    for(;la<=ra;la++,lb++){
        if(s[a][la]!=s[b][lb])
            return 0;
    }
    return 1;
}
inline bool revmatch(int a,int la,int ra,int b,int lb,int rb){
    for(;la<=ra;la++,rb--){
        if(s[a][la]!=s[b][rb])
            return 0;
    }
    return 1;
}
bool check(int x){
    for(int i=1;i+x-1<=len[1];i++){
        bool find=1;
        for(int j=2;j<=N;j++){
            bool vis=0;
            for(int k=1;k+x-1<=len[j];k++)
                if(match(1,i,i+x-1,j,k,k+x-1)||revmatch(1,i,i+x-1,j,k,k+x-1)){
                    vis=1;
                    break;
                }
            if(!vis){
                find=0;
                break;
            }
        }
        if(find)
            return 1;
    }
    return 0;
}
int main(){
    freopen("in.txt","r",stdin);
    int T;
    cin>>T;
    while(T--){
        int re = 0;
        cin>>N;
        for(int i = 1; i <= N; i++){
            scanf("%s",s[i]+1);
            len[i]=strlen(s[i]+1);
        }
        L = len[1];
        for(int i = 1; i <= L; i++){
            if(check(i)) re = max(re,i);
        }
        cout<<re<<endl;
    }
    return 0;
}
//1007
//考虑前缀问题,句子是th,字典是t不应翻译
#include <iostream>
#include <map>
#include <string>
#include <cstring>
using namespace std;
string s,ss;
string t;
string st="START",en="END",nul="\0";
map<string,string> mp;
char str[3010];
bool oo(char c){//是否原样输出
    if(c >= 'a' && c<='z') return 0;
    else return 1;
}
int main(){
    freopen("in.txt","r",stdin);
	cin>>s;
    if(s==st){
        while(1){
            cin>>s;
            if(s==en) break;
            cin>>ss;
            mp[ss]=s;
        }
    }
    cin>>s;
    getchar();//gets前要去掉字符
    if(s==st){
        while(1){
            t = "";
            gets(str);
            int lens = strlen(str);
            if(str==en) break;
            for(int i = 0; i < lens;i++){
                if(oo(str[i])){//特殊字符原样输出
                    if(mp[t] != nul){//找到了字典里的
                        t = mp[t];
                    } 
                    cout<<t;
                    putchar(str[i]);
                    t = "";
                }
                else{                 
                    t += str[i];                     
                }
            }
            if(t!=nul) cout<<t;
            cout<<endl;
        }
    }
    return 0;
    // map<string,string>::iterator it;
    // for(it = mp.begin(); it != mp.end(); it++){
    //     cout<<it->first<<";"<<it->second<<endl;
    // }
}

//1008
#include <bits/stdc++.h>
using namespace std;
bool vis[21];
int a[21];
int n,cas = 0;
bool isprime[50];
void get_prime(int n=40){
    memset(isprime,1,sizeof(isprime));
    isprime[0]=isprime[1]=0;
    for(int i=2;i<=n;i++){
        if(isprime[i])
            for(int j=i+i;j<=n;j+=i)
                isprime[j]=0;
    }
}
void dfs(int t){
    if(t == n+1 && isprime[a[n]+a[1]]){
        for(int i = 1; i <= n; i++){
            if(i<n) cout<<a[i]<<" ";
            if(i == n) cout<<a[i]<<endl;
        }
        
    }
    else{
        for(int j = 2; j <= n; j++){
            if(!vis[j]){
                if(isprime[a[t-1]+j]){
                    a[t] = j;
                    vis[j] = 1;
                    dfs(t+1);
                    vis[j] = 0;
                }
                
            }
        }
    }
}
int main(){
    freopen("in.txt","r",stdin);
    get_prime();
    while(cin>>n){
        cas++;
        cout<<"Case "<<cas<<":"<<endl;
        memset(vis,0,sizeof(vis));
        a[1]=1; vis[1]=true;
        dfs(2);
        cout<<endl;
    }
    return 0;
}
//1009
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
int n,m,step;
const int maxn = 110;
char G[maxn][maxn];
bool vis[maxn][maxn];
int dic[maxn][maxn]; //回溯用
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0}; //右下左上
string s = " seconds to reach the target position, let me show you the way.";
struct NODE{
    int x;
    int y;
    int step;
    friend bool operator<(NODE n1,NODE n2){
        return n1.step>n2.step;//默认大根堆,要反着写
    }
}node,cur,nextt,way[10001];
bool out(int x,int y){
    if(x<1 || y<1 || x>n || y>m) return 1;
    if(vis[x][y]) return 1;
    if(G[x][y]=='X') return 1;
    return 0;
}
int bfs(int x,int y){
    priority_queue<NODE> q; //优先级队列,小根堆
    cur.x = x;cur.y = y;cur.step = 0;
    q.push(cur);
    while(!q.empty()){
        cur = q.top();
        q.pop();
        int cx=cur.x,cy=cur.y,cstep=cur.step;
        //完成
        if(cx==n && cy==m) return cstep;
        for(int i = 0; i < 4; i++){
            int xx = cx+dx[i];
            int yy = cy+dy[i];
            if(out(xx,yy)) continue;
            vis[xx][yy] = 1;
            dic[xx][yy] = i;
            if(G[xx][yy] == '.'){
                nextt.x=xx; nextt.y=yy; nextt.step=cstep+1;
            }
            else{//怪兽
                int hp = G[xx][yy] - '0';
                nextt.x=xx; nextt.y=yy; nextt.step=cstep+1+hp;
            }
            q.push(nextt);
        }
    }
    return 0;
}
int main(){
    //freopen("in.txt","r",stdin);
    while(cin>>n>>m){
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m; j++){
                cin>>G[i][j];
            }
        }
        memset(vis,0,sizeof(vis));
        vis[1][1]=1;
        step = bfs(1,1); //遍历得到step
        if(step){
            int cx = n,cy = m;
            for(int i = step; i > 0; i--){
                way[i].x = cx; 
                way[i].y = cy;
                if(G[cx][cy]>='1' && G[cx][cy]<='9'){
                    int hp = G[cx][cy] - '0';
                    for(int j = 1; j <= hp; j++){
                        way[i-j].x=cx;
                        way[i-j].y=cy;
                    }
                    i = i - hp;
                }
                switch(dic[cx][cy]){
                    case 0: cy--; break;
                    case 1: cx--; break;
                    case 2: cy++; break;
                    case 3: cx++; break;
                }
            }
            cout<<"It takes "<<step<<s<<endl;
            cout<<"1s:(0,0)->("<<way[1].x-1<<","<<way[1].y-1<<")"<<endl;
            for(int i = 2; i <= step; i++){
                if(way[i].x==way[i-1].x && way[i].y==way[i-1].y)
                    cout<<i<<"s:FIGHT AT ("<<way[i].x-1<<","<<way[i].y-1<<")"<<endl;
                else
                    cout<<i<<"s:("<<way[i-1].x-1<<","<<way[i-1].y-1<<")->("<<way[i].x-1<<","<<way[i].y-1<<")"<<endl;
            }
        }
        else cout<<"God please help our poor hero."<<endl;
        cout<<"FINISH"<<endl;
    }
    return 0;
}
//1010(感谢大佬代码)
//题解:https://blog.csdn.net/hexiaole1994/article/details/80997090
#include <bits/stdc++.h>
using namespace std;
const int maxn = 101;
int m,n;
int dp[maxn][maxn];
int main(){
    freopen("in.txt","r",stdin);
    int cas = 1;
    while(cin>>m>>n,m+n){
        memset(dp,0,sizeof(dp));
        dp[0][0]=1;
        for(int i = 1; i <= m; i++){
            dp[i][0]=dp[i-1][0]*(m-i+1);  //m*(m-1)*...*(1)
        }
        for(int i = 1; i <= m; i++){
            for(int j = 1; j <= min(i,n); j++){//100元不能大于当前50元拥有的数目,否则不够找
                dp[i][j]=dp[i][j-1]*(n-j+1)+ dp[i-1][j]*(m-i+1);
            }
        }
        cout<<"Test #"<<cas++<<":"<<endl;
        cout<<dp[m][n]<<endl;
    }
}
//1011(感谢大佬代码)
/* 一n个节点的树,树的每个节点上可能有一些bug。
你有m组军队,每组军队可以处理一个节点的20个bug,
处理掉一个节点的所有bug会有一定收益,
你从1号节点出发,可以分兵,进入下一个节点之前必须解决掉当前节点的bug。
求你能获得的最多收益。
树形动态规划,转移类似背包。*/
//f[i][j]表示在以i为根的子树上,分配j组兵能获得的最大收益。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
#define Max 102
struct node
{
    int bugs,val;
}cav[Max];
vector<int> node[Max];
int n,m;
int vis[Max],dp[Max][Max];
int a,b;
void dfs(int p)
{
    int i,j,k;
    vis[p]=1;
    int temp=(cav[p].bugs+19)/20;
    for(i=temp;i<=m;i++) dp[p][i]=cav[p].val;
    for(i=0;i<node[p].size();i++){
        int t=node[p][i];
        if(vis[t]) continue;
        dfs(t);                    
        for(j=m;j>=temp;j--)            //回溯时完成对该点的动态规划
            for(k=1;k<=j-temp;k++)
                dp[p][j]=max(dp[p][j],dp[p][j-k]+dp[t][k]);        //保证父节点能够占领
    }
    return;
}
int main()
{
    int i,j;
    freopen("in.txt","r",stdin);
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(n==-1&&m==-1)
            break;
        memset(vis,0,sizeof(vis));
        memset(dp,0,sizeof(dp));
        for(i=0;i<=n;i++)    node[i].clear();
        for(i=1;i<=n;i++)
            scanf("%d%d",&cav[i].bugs,&cav[i].val);
        for(i=0;i<n-1;i++)
        {
            scanf("%d%d",&a,&b);
            node[a].push_back(b);
            node[b].push_back(a);
        }
        if(m==0)
        {
            printf("0\n");
            continue;
        }
        dfs(1);
        printf("%d\n",dp[1][m]);
    }
    return 0;
}
//1012
#include <bits/stdc++.h>
using namespace std;
int T;
char s[72];
int main(){
    freopen("in.txt","r",stdin);
    cin>>T;
    getchar();
    while(T--){
        gets(s);
        int len = strlen(s);
        for(int i = len-1; i >= 0; i--) cout<<s[i];
        cout<<endl;
    }
    return 0;
}
//1013(感谢李震大佬提供elegant code)
#include <bits/stdc++.h>
using namespace std;
int N,M;
bool succ;
void dfs(int x,long long a,long long b){
    if(x==101||succ)return; //叶结点
    if(N%a||M%b)return; //剪枝:如果不在公约数的范围内
    if(a==N&&b==M){ //无公共因子,大数胜利
        succ=1;
        return;
    }
    dfs(x+1,a*x,b);
    dfs(x+1,a,b*x);
    dfs(x+1,a,b); //这个数ab都没取
}
int main(){
    freopen("in.txt","r",stdin);
    while(scanf("%d%d",&N,&M)!=EOF){
        if(N>M)swap(N,M);
        succ=0;
        dfs(2,1,M);
        if(!succ){
            printf("%d\n",M);
            continue;
        }
        succ=0;
        dfs(2,1,1); //搜索有无公共因子(分低有可能说谎)
        if(succ)printf("%d\n",M);
        else printf("%d\n",N);
    }
    return 0;
}
//1014
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
typedef pair<int,int> P;
int k[205];
int vis[205];
int N,A,B;
int dfs()
{
	vis[A]=1;
	queue<P> que;
	que.push(P(0,A));
	while(!que.empty())
	{
		P now=que.front();que.pop();
		if(now.second==B)
		{
			return now.first;
		}
		for(int i=-1;i<=1;i++)
		{
			int next=now.second+i*k[now.second];
			if(1<=next&&next<=N&&!vis[next])
			{
				vis[next]=1;
				que.push(P(now.first+1,next));
			}
		}
	}
	return -1;
}
int main()
{
	while(scanf("%d",&N)!=EOF&&N!=0)
	{
		scanf("%d %d",&A,&B);
		for(int i=1;i<=N;i++)
		{
			scanf("%d",&k[i]);
		}
		memset(vis,0,sizeof(vis));	
		printf("%d\n",dfs());
	}
	
    return 0;
}
//1015
#include<bits/stdc++.h>
using namespace std;
const int maxn=25;
int A,N,a[maxn];
bool succ,use[maxn];
bool cmp(const int&x,const int&y){
    return x>y;
}
void dfs(int x,int sum,int p){
    if(x==4){
        succ=1;
        return;
    }
    if(succ)return;
    if(sum==A){
        dfs(x+1,0,0);
        return;
    }
    for(int i=p+1;i<=N;i++)
        if(!use[i]&&a[i]+sum<=A){
            use[i]=1;
            dfs(x,sum+a[i],i);
            use[i]=0;
        }
}
int main(){
    freopen("in.txt","r",stdin);
    int T;
    cin>>T;
    while(T--){
        cin>>N;A=0;
        for(int i=1;i<=N;i++)
            cin>>a[i],A+=a[i];
        if(A%4)
            puts("no");
        else{
            sort(a+1,a+1+N,cmp);
            A/=4;succ=0;
            dfs(1,0,0);
            if(succ)
                puts("yes");
            else
                puts("no");
        }
    }
    return 0;
}

(完)

特别鸣谢:感谢李震以及各位大佬的代码,如有错误,请您包涵

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值