目录

目录

  • 第六讲——数据结构基础
    • 6.1栈和队列
      • 例题6-2 UVa514
      • 例题6-3 UVa442
    • 6.2链表
      • 例题6-4 UVa11988
      • 例题6-5 UVa12657
    • 6.3树和二叉树
      • 例题6-6 UVa679
      • 例题6-9 UVa839
      • 例题6-10 UVa699
    • 6.4图
      • 例题6-15 UVa10305
      • 例题6-16 UVa10129
  • 第七讲——暴力枚举
    • 7.1简单枚举
      • 例题7-1 UVa725
      • 例题7-2 UVa11059
      • 例题7-3 UVa10976
    • 7.1回溯法
      • 例题7-4 UVa524
      • 例题7-5 UVa129
      • 例题7-6 UVa140
      • 例题7-7 UVa1354
    • 7.5 路径寻找问题
      • 例题7-8 UVa1354
      • 例题7-9 UVa1601
    • 7.6 迭代加深搜索
      • 例题7-9 UVa1601
      • 例题7-10 UVa11212
  • 第八讲——高效算法设计
  • 第九讲——动态规划初步
    • 9.1 数字三角形
      • 9.1.1数字三角形
      • 数字三角形
    • 9.2 DAG上的动态规划
      • 9.2.1DAG模型
      • 矩形嵌套问题
      • 硬币问题
      • 9.2.4 小结与应用举例
      • 例题9.2 巴比伦塔
    • 9.3 多阶段决策问题
      • 9.3.1 多段图的最短路
      • 例题9.4 单项TSP
      • 9.3.2 0-1背包问题
      • 物品无限的背包问题(完全背包)
      • 0-1背包问题
      • 例题9.5 劲歌金曲
    • 9.4 更多经典模型
      • 9.4.1 线性结构上的动态规划
        • 9.4.1 最长上升自序列(LIS)
  • 连环大跳(跳了很多)
  • 第十讲——数据结构基础
    • 10.1 数论初步
      • 10.1.1 欧几里得算法和唯一分解定理

第六讲——数据结构基础

6.1栈和队列

例题6-2 UVa514

我就是入门半年,还没入门成功的大——

从现在起开始认真刷紫薯(其实是抄紫薯哈哈哈)
每道题的理解都在代码里面。
我是真的弱,如果我有错误,评论里留下你的大名,我一定记在我的报答簿上。

正文


让我们一起————入门到入土
话不多说,立马进入正题
不愧是大佬,思路如此清晰
后知后觉——好像应该挂出链接——戳我戳我

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
using namespace std;
#define mid   100007
typedef long long ll;
//紫薯上的题
//就是看出栈顺序能够不能实现
//1。检测此时该入栈的数是否对
//2.检测栈顶的数是否对
//3.两者都不满足就入栈(这样就可以调换顺序)
//tips:为了学好思路,这些都是请参考过紫薯的,不过代码是自己打的
int main(){int a,c[1006],i,t;while(cin>>a&&a!=0){while(1){t=0;cin>>c[1];if(c[1]==0)break;  for(i=2;i<=a;i++)cin>>c[i];//这是要求最后的顺序 stack<int>w;int e=1,f=1;while(e<=a)/*全部输出都能够一一对应*/{if(f==c[e])e++,f++;//满足1else if(!w.empty()/*栈里有东西*/&&w.top()==c[e]){w.pop();e++;}else if(f<=a)/*保证还可以入栈,就可以换顺序*/{w.push(f);f++;} else /*上面都不满足就不可能了*/{t=1;break;} }printf("%s\n",t==0?"Yes":"No");}cout<<endl;//注意输出格式
}
return 0;
}

代码抽风还请指证,有啥直接告诉我,我家就住在CSDN

例题6-3 UVa442

构造函数的使用

(**其实我是才学过,但是没用过,也不知道怎么用 **)
废话不多说上代码(题目通道)

图片大小调不了吗?

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
using namespace std;
#define mid   100007
typedef long long ll;
//还是紫薯上的题
//还是用栈实现
/*思路就是字母也入栈,一遇到“)”就进行判断
判断此时顶端的两个乘,如果不能乘,就直接错误,输出error
否则,sum加上,然后把两个相乘后矩形重新放入栈,其实整个过程
没有“()”入栈的情况,嘿嘿
思路清晰,不愧是大佬*/
struct www{int hang;int lie;www(int hang=0,int lie=0):hang(hang),lie(lie){}//这个就是精华,我见都没见过,后面有大作用 //猛男醒悟,这就是我才学的构造函数,居然结构体内也可以用,我还一直以为没有用
}c[30];//记录矩阵
int main(){int a,i,sum,t;char b;cin>>a;while(a--){//朴素的输入 cin>>b;cin>>c[b-'A'].hang>>c[b-'A'].lie; }string s;stack<www>k;//建立栈 while(cin>>s){sum=0,t=0;for(i=0;i<s.size();i++){if(isalpha(s[i]))k.push(c[s[i]-'A']);//是字母就入栈else if(s[i]==')'){//"("没有用,牛逼,大佬 //我看紫薯上的程序也没判断出栈时元素不足两个的情况 www p=k.top();k.pop();www q=k.top();k.pop();//取出最上面两个if(q.lie!=p.hang){t=1;break;}//注意顺序 else{sum+=q.hang*q.lie*p.lie;k.push(www(q.hang,p.lie));/*这就是精华,怎样通过,q.a,p.b再放入栈还*/ }}}if(t==1)cout<<"error"<<endl;else cout<<sum<<endl;
}
return 0;
}

我写代码真是一点都不好看
罪过罪过

慢着,我好像明白了这个构造函数
它其实就是用传进去的两个参数重新构造了一个www变量
字母只是一个表壳,内在就是这个www变量
ohhhhhhhhhhhhhhhhhh

6.2链表

例题6-4 UVa11988

本来使用链表,
可我不想用
其实是我看了好久,都想不通
就屈服于STL的伟大,用list
感觉确实有点慢,链表实现我下次补。
下次一定
血池

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<list>
using namespace std;
#define mid   100007
typedef long long ll;
//还是紫薯上的题
//无奈本人太菜鸡,这个链表怎么也想不通
//就先放过自己,用list
//早知道就用这个了,又浪费傻子几小时
int main(){int i;string s;while(cin>>s){list<char>w;list<char>::iterator it =w.begin();for(i=0;i<s.size();i++){if(s[i]=='['){it=w.begin();//从前面 }else if(s[i]==']'){it=w.end();//从后面 }else{//进入list w.insert(it,s[i]); }}for(it=w.begin();it!=w.end();it++)cout<<*it;cout<<endl;}return 0;
}

对不住了。我看了一下下面一道链表,好像更难
只有先行略过了
菜鸡跳题,毫不犹豫
假装**第四滴血**

例题6-5 UVa12657

6.3树和二叉树

例题6-6 UVa679

大树
周树人
“抓捕周树人和我鲁迅有什么关系”

小球下落

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<list>
using namespace std;
#define mid   100007
typedef long long ll;
/*
//二叉树,简单模拟
int c[1<<20];//1向左移动20位就相当于pow(2,20);
//最大节点个数[(1<<20)-1]
int main(){int a,b,k;while(scanf("%d%d",&a,&b)==2){memset(c,0,sizeof(c));//开关清零int maxmax=(1<<a)-1;//最大结点的标号while(b--){//让b个球挨个下落 k=1;//从1开始落 for(;;){//一开始还以为会超时, c[k]=!c[k];//开变关,关变开k=c[k]?2*k:2*k+1;//节点与两个子节点的关系 if(k>maxmax)break; }}//出界之前的位置 cout<<k/2<<endl;//2*k,2*k+1的1/2都是k } return 0;
}
*/
//上面的会超时,应为他每一个小球都模拟了,浪费了大量时间
//其实我们只用知道小球的编号就可与以知道他的路径
//当在1节点时,编号为偶数,就会走右边,否则走左边
//每个节点都是这个道理
int main(){int a,b,k,p;cin>>p;while(p--){cin>>a>>b;k=1;a--;//只能下降a-1次 while(a--){if(b%2==1){k*=2;//左树比右树多走一个 ,因为每次先走左数 b=(b+1)/2;}else{k=k*2+1;b/=2;}}cout<<k<<endl; }cin>>p;return 0;
}

例题6-9 UVa839

前面跳了两道题,
都是构造树的?没看明白
**菜鸡跳题,毫不犹豫 **
跳的两道题
第一道
第二道

紫薯的思路真的好清晰

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<list>
using namespace std;
#define mid   100007
typedef long long ll;
//紫薯继续
//看题是递归输入,就是个模拟
bool sou(int &k){//才学的引用 ,k值可以进行修改   int e,f,g,h; bool p=true; bool q=true; cin>>e>>f>>g>>h;if(e==0){//左手是个子树 p=sou(e);//记录左边的重量 ,看左边是不是平衡的 }if(g==0){q=sou(g);//记录右边的重量 ,看右边是不是平横的 }k=e+g;return q&&p&&f*e==g*h;//左右和自己都平衡才是平衡
}
int main(){int a,k=0;cin>>a;while(a--){if(sou(k)) cout<<"YES"<<endl;elsecout<<"NO"<<endl;if(a)cout<<endl;}return 0;
}

例题6-10 UVa699

有两个小坑点就是
1.函数记得要有返回值
2.UVA的题对于输出格式好像很严格,行尾有空格都不行
紫薯上就没有没有,导致一直RE
题目传送门

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<list>
using namespace std;
#define mid   100007
typedef long long ll;
//紫薯继续
//多用bool类型
int c[200];
//储存每个水平面的值
void jian(int a){int b;cin>>b;if(b!=-1)c[a]+=b;elsereturn ;//等于-1就是没有路了,直接返回 jian(a-1);//先左 jian(a+1);//后右
}
bool du(){//对第一个节点进行特殊处理int a;cin>>a;if(a==-1)return false;memset(c,0,sizeof(c));//因为多组输入 c[200/2]=a;//第一个节点处于最中间的位置 jian(200/2-1);//先左 jian(200/2+1);//后右 return true;
}
int main(){int t=1;while(du()){int i=0;while(c[i]==0)i++;cout<<"Case "<<t++<<":"<<endl<<c[i++];while(c[i]!=0)cout<<" "<<c[i++];cout<<endl<<endl; }return 0;
}

6.4图

例题6-15 UVa10305

Kahn算法实现

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
#define mid 1000000007
typedef  long long ll;
// 紫薯继续(和平精英千年老二)
//拓扑排序
int du[106],a,b;//记录每个点的入度
vector<int>c[106];//邻接表
int ans[106];//记录答案
void sou(){int k=0,i;queue<int>p;for(i=1;i<=a;i++)//寻找出度为0的点if(du[i]==0)p.push(i);/*放进队列,因为每次开始处理都是从入度为0点开始*/ while(!p.empty()){int xin=p.front();p.pop();ans[++k]=xin;//记录答案/*上面清除了一个入度为0的点,下面要把与之所相连的得点入度给剪掉 */for(i=0;i<c[xin].size();i++){du[c[xin][i]]--;if(du[c[xin][i]]==0){/*如果这时候产生一个新的入度为0 的点 */ p.push(c[xin][i]); }} } for(i=1;i<=a;i++){if(i==1)cout<<ans[i];elsecout<<" "<<ans[i];}cout<<endl;
//  if(k!=a)//说明这个环
//   return 0;
//   else
//   return 1;
}
int main(){int e,f;while(scanf("%d%d",&a,&b)==2){if(a==b&&b==0)break;for(int i=1;i<=a;i++){c[i].clear();//临接表清空 }memset(du,0,sizeof(du)); while(b--){cin>>e>>f;du[f]++;//先完成e,才能再完成fc[e].push_back(f);//e->f }sou();}return 0;
}

也可以DFS实现

例题6-16 UVa10129

欧拉回路
本题思路

//用并查集实现
//1.要查询每个点的祖先,有多个祖先的就无法形成通路(判断通路)
//2.有两个点的出度与入度不相等,且相差1。或者每个点出度入度都等
例如 asdsdb bsadjasjda

这个UVa今天交不上去啊
先把代码挂在这里

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
#define mid 1000000007
typedef  long long ll;
// 紫薯继续(和平精英千年老二)
//把单词看成有向边,单词开头末尾看作节点
//用并查集实现
//1.要查询每个点的祖先,有多个祖先的就无法形成通路(判断通路)
//2.有两个点的出度与入度不相等,且相差1
int f[30];//记录祖先节点
int ru[30],chu[30],book[30];
int zu(int a){//寻找祖先节点 if(a!=f[a])return f[a]=zu(f[a]);elsereturn  a;
}
void chushihua(){memset(ru,0,sizeof(ru));memset(chu,0,sizeof(chu));memset(book,0,sizeof(book));for(int i=1;i<=26;i++){f[i]=i;}
}
int main(){int a,b,i,ans,r,ch,t;cin>>a;while(a--){r=ch=t=ans=0; chushihua();cin>>b;while(b--){string s;cin>>s;int p=s[0]-'a'+1;int q=s[s.size()-1]-'a'+1;ru[p]++;chu[q]++;int w=zu(p);int z=zu(q);if(w!=z)f[z]=w;//合并 book[p]=book[q]=1;//记录有这个点 }for(i=1;i<=26;i++){if(book[i]){/*看看有几个祖先节点,只有一个才能形成通路*/if(f[i]==i)ans++;//祖先节点+1if(ru[i]!=chu[i]){if(ru[i]-chu[i]==1)r++;else if(chu[i]-ru[i]==1)ch++;//合法的出入度不同就这两种,其他都不正确 elset=1; }//判段if(t||ans>1){break;}}}if(i!=27)cout<<"The door cannot be opened."<<endl;else{if((r==1&&ch==1)||(r==ch&&r==0))cout<<"Ordering is possible."<<endl; elsecout<<"The door cannot be opened."<<endl;}}
}

第七讲——暴力枚举

7.1简单枚举

例题7-1 UVa725

只用枚举前5个数,后五个数会自动形成
最后再判断一下数字是否重复

前排提示:UVA对输出格式有控制,WA死我了

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
#define mid 1000000007
typedef  long long ll;
// 紫薯继续(和平精英千年老二)
//暴力也需要优化!
/*直接枚举分子就行,
分母也可以得出,
最后看看有没有重复就行*/
int book[12],a,sum=0,book1[12],t;//两个book,标记两个数
void sou(int b){if(b==6){if(sum%a!=0)return ;//找不到整数被除数int k=sum/a;int q=k;/*记录这个数,因为后面判段数字是否重复时会改变 如果判断没有错误,就可以直接输出*/ //分解k,看是否有元素重合memset(book1,0,sizeof(book1)); for(int i=1;i<=5;i++){if(book[k%10]==1||book1[k%10]==1)//出现过了 return ;book1[k%10]=1; k/=10;}t++;printf("%05d / %05d = %d\n",sum,q,a);return ;}//枚举 for(int i=0;i<=9;i++){int p=sum;if(book[i]==0){sum=sum*10+i;book[i]=1;sou(b+1);sum=p;book[i]=0;}//恢复原来状态}
}
int main(){int w=0;//执行的次数,因为最后输出不带\n while(scanf("%d",&a)&&a){if(w)cout<<endl;w++; memset(book,0,sizeof(book));t=0;sou(1);if(t==0)printf("There are no solutions for %d.\n",a);}return 0;
}

例题7-2 UVa11059

数据比较小,也就是个枚举
枚举起点和终点
终点动态变换,起点固定
两重循环就可以了

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
#define mid 1000000007
typedef  long long ll;
// 紫薯继续(和平精英千年老二)
//就是枚举,没别的
ll c[20];
int main(){ll a,i,j,b;ll sum,maxmax,k=0,p;while(scanf("%lld",&a)!=EOF){maxmax=0;for(i=1;i<=a;i++)scanf("%lld",&c[i])A;for(i=1;i<=a;i++){//起点 sum=1;for(j=i;j<=a;j++){//终点移动 sum*=c[j];maxmax=max(sum,maxmax);}}printf("Case #%d: The maximum product is %lld.\n\n", ++k, maxmax);}return 0;
} 

例题7-3 UVa10976

数学分析走着
解不等式
x=>2a>=y

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
#define mid 1000000007
typedef  long long ll;
// 紫薯继续(和平精英千年老二)
//数学题?
//解不等式——解出   x=>2a>=y
int c1[10000];
int main(){int a,y,p;while(scanf("%d",&a)!=EOF){p=0;for(y=1;y<=2*a;y++){//y的取值范围//式子变换——a=xy/(x+y) //x=ay/(y-a) if(y-a>0&&(a*y)%(y-a)==0&&(a*y)/(y-a)!=0){c1[++p]=y;//记录答案}}cout<<p<<endl;for(int i=1;i<=p;i++)printf("1/%d = 1/%d + 1/%d\n",a,(a*c1[i])/(c1[i]-a),c1[i]); }return 0;
}

7.1回溯法

例题7-4 UVa524

前排恭喜vj上UVa连炸两天

素数环
回溯法
记住最后还要和环首 1 进行判断

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
#define mid 1000000007
typedef  long long ll;
//素数处理
int book[20];//标记数组
int ans[20];//记录答案
int su[50];//记录素数
int a;
void sushu(){for(int i=1;i<=50;i++){for(int j=2;j*j<=i;j++){if(i%j==0){su[i]=1;//素数标记为0break; }}}
}
void sou(int b){if(b==a+1){if(su[ans[b-1]+1]==0){//因为是环状,所以还要与开头 1 判断for(int i=1;i<=a;i++){if(i!=a)//注意输入输出格式cout<<ans[i]<<" ";elsecout<<ans[i];}cout<<endl;return ;}}for(int i=2;i<=a;i++){if(book[i]==0&&su[i+ans[b-1]]==0){book[i]=1;ans[b]=i;sou(b+1);//回溯book[i]=0; }}
}
int main(){int k=0;sushu();while(scanf("%d",&a)!=EOF){if(k!=0)cout<<endl;//注意输入输出格式 printf("Case %d:\n",++k);//第一个数为 1ans[1]=1;sou(2);}
}

例题7-5 UVa129

UVa的输入输出格式是真的难搞

注意子串相等时是怎样比较的
还是回溯法
每次添加一个字母进入字符串,最终顺序就是升序
我有点写不明白,还是自己看吧

紫薯上的一句话:
回溯法中,
应注意不必要的判断,
就像八皇后,每次只用判断新皇和之前的皇是否冲突,而不用判断以前的皇后是否冲突,因为以前已经判断过了

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
typedef  long long ll;
//这紫薯看的我天天喊牛皮
//回溯的思想
//每次添加一个字母
int w=0;//记录第几个困难串
int a,b,t;
char ans[100];//记录答案
int jian(int c){int mid=c/2;//枚举比较的字串长度int i,j,p;for( i=1;i<=mid;i++){for( j=c+1-2*i,p=c+1-i;p<=c;j++,p++){//两个字串比较是否相等 if(ans[j]!=ans[p])//字串不相等 break; }if(p==c+1)//字串相等return 0; }return 1;
}
void dfs(int c){if(t==1)return ; if(++w==a){/*每次只要进行了dfs函数都会产生一个新的排列所以w++;*/ t=1;//令人烦躁的输出for(int i=1;i<c;i++){cout<<ans[i]; if(i%4==0&&i!=c-1){if(i%64==0)cout<<endl;elsecout<<" ";}}cout<<endl<<c-1<<endl;return ;}for(int i=0;i<b;i++){ans[c]=i+'A';if(jian(c))//如果检查没有重复,就继续下一个dfs(c+1); //只要继续dfs,就是产生了一个排列 //否则就重新选择 }
}
int main(){while(scanf("%d%d",&a,&b)&&b&&a){//平平无奇的输入 w=-1;t=0;dfs(1);}return 0;
}

例题7-6 UVa140

例题7-7 UVa1354

这两个题我愣是没读懂题

7.5 路径寻找问题

例题7-8 UVa1354

烦躁

代码是我抄的,加了点解释
看着比紫薯上好懂
虽然长了点,但有一大段“重复的”

#include <iostream>
#include <queue>
#include <cstring>
#include <cstdio>
/*看紫薯的题解有点抽风,我的木鱼脑袋接受不了
找的其他题解 */
using namespace std;const int MAXN = 200;int a, b, c, d, maxd1, minamount;
bool notvist[MAXN+1][MAXN+1][MAXN+1];struct node {//记录每一个状态int a, b, c, amount;bool operator < (const node& n) const {return amount > n.amount;}//这个是干嘛的??????????????????
};int bfs()
{maxd1 = 0;minamount = 0;//因为是对移动水最少的进行扩展,所以使用优先队列 priority_queue<node> q;//多组输入,标记数组清零 memset(notvist, true, sizeof(notvist));node f, v;f.c = c;f.a = 0;f.b = 0;f.amount=0;//标记初始状态 q.push(f);notvist[f.c][f.a][f.b] = false;//下面进行扩展while(!q.empty()) {f = q.top();//优先队列这里是topq.pop();if(f.a == d || f.b == d || f.c == d)return f.amount;//找到结果,直接退出dfsif(f.a < d && f.a > maxd1) {maxd1 = f.a;minamount = f.amount;}if(f.b < d && f.b > maxd1) {maxd1 = f.b;minamount = f.amount;}if(f.c < d && f.c > maxd1) {maxd1 = f.c;minamount = f.amount;}/*用三个if寻找倒在杯子里的不大于h的最大值顺便记录步数 */// 下面枚举6中操作,大同小异//用v记录操作后的状态 // c --> aif(f.c && a - f.a > 0) {if(f.c > a - f.a) {         // c > a的剩余容量v.c = f.c - (a - f.a);v.a = a;v.b = f.b;v.amount = f.amount + (a - f.a);} else {                    // c <= a的剩余容量v.c = 0;v.a = f.a + f.c;v.b = f.b;v.amount = f.amount + f.c;}if(notvist[v.c][v.a][v.b]) {notvist[v.c][v.a][v.b] = false;q.push(v);}}// c --> bif(f.c && b - f.b > 0) {if(f.c > b - f.b) {         // c > b的剩余容量v.c = f.c - (b - f.b);v.a = f.a;v.b = b;v.amount = f.amount + (b - f.b);} else {                    // c <= b的剩余容量v.c = 0;v.a = f.a;v.b = f.b + f.c;v.amount = f.amount + f.c;}if(notvist[v.c][v.a][v.b]) {notvist[v.c][v.a][v.b] = false;q.push(v);}}// a --> cif(f.a && c - f.c > 0) {if(f.a > c - f.c) {         // a > c的剩余容量v.c = c;v.a = f.a - (c - f.c);v.b = f.b;v.amount = f.amount + (c - f.c);} else {                    // a <= c的剩余容量v.c = f.c + f.a;v.a = 0;v.b = f.b;v.amount = f.amount + f.a;}if(notvist[v.c][v.a][v.b]) {notvist[v.c][v.a][v.b] = false;q.push(v);}}// a --> bif(f.a && b - f.b > 0) {if(f.a > b - f.b) {         // a > b的剩余容量v.c = f.c;v.a = f.a - (b - f.b);v.b = b;v.amount = f.amount + (b - f.b);} else {                    // a <= b的剩余容量v.c = f.c;v.a = 0;v.b = f.b + f.a;v.amount = f.amount + f.a;}if(notvist[v.c][v.a][v.b]) {notvist[v.c][v.a][v.b] = false;q.push(v);}}// b --> cif(f.b && c - f.c > 0) {if(f.b > c - f.c) {         // b > c的剩余容量v.c = c;v.a = f.a;v.b = f.b - (c - f.c);v.amount = f.amount + (c - f.c);} else {                    // b <= c的剩余容量v.c = f.c + f.b;v.a = f.a;v.b = 0;v.amount = f.amount + f.b;}if(notvist[v.c][v.a][v.b]) {notvist[v.c][v.a][v.b] = false;q.push(v);}}// b --> aif(f.b && a - f.a > 0) {if(f.b > a - f.a) {         // b > a的剩余容量v.c = f.c;v.a = a;v.b = f.b - (a - f.a);v.amount = f.amount + (a - f.a);} else {                    // b <= a的剩余容量v.c = f.c;v.a = f.a + f.b;v.b = 0;v.amount = f.amount + f.b;}if(notvist[v.c][v.a][v.b]) {notvist[v.c][v.a][v.b] = false;q.push(v);}}}return -1;
}int main()
{int t;scanf("%d", &t);while(t--) {scanf("%d%d%d%d", &a, &b, &c, &d);int ans = bfs();if(ans < 0) {printf("%d %d\n", minamount, maxd1);} elseprintf("%d %d\n", ans, d);}return 0;
}

例题7-9 UVa1601

双向BFS
不会

7.6 迭代加深搜索

例题7-9 UVa1601

真的佩服看了大量题解看不懂,突然有个大佬的题解明白了
在线跪
牛逼

总结一下
这是那个大佬的题解链接

什么狗屁迭代加深搜索,看的我懵逼了一早上
这个也没涉及什么算法,所以看了还是好懂,但是叫我自己写,肯定写不出来
题目最重要的是每次搜索规定了上下界
还有好多小细节:多用乘法代替除法…
大佬真强

我改了一些细节

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<set>
//真的是难,我要吐了
//真的是半天一道题,还是看的别人的代码
//大佬思路
using namespace std;
const int N=1e5+7;
set <long long> p;
long long t,A,B,n,mxdep;
long long ans[N],w[N];
bool flag;
//inline long long gcd(long long a,long long b)
//{//    return b ? gcd(b,a%b) : a;
//}//gcd是为了约分
inline bool pd()
{for(int i=mxdep;i;i--)if(ans[i]!=w[i])return ans[i]&&ans[i]<w[i];return 0;
}//判断答案是否更优
inline void dfs(long long dep,long long a,long long b,long long mi)
{if(dep==mxdep)//还剩最后一个数时 {if(b%a||(b*mi<a)||p.count(b/a)) return;//判断合法性//不合法 /*判断合法性的三个条件 1.可以构成1/n形式2.比mi小3.b/a这个数可以使用*/ //如果合法还要看是否为最优情况w[dep]=b/a;if(pd()) return;//判断答案是否更优memcpy(ans,w,sizeof(w)); flag=1;//更新return;}mi=max(mi,b/a+1);//求出下界for(long long i=mi;i;i++){if( (mxdep-dep+1)*b<=i*a ) return;/*因为每个选择的数其实大小是递减的,如果这个数和以后的数分母都用i的和都比a/b小,那就肯定实现不了后面更大的i就更不用再考虑了*//*用乘法表示的的优势在于不用害怕除法的精度丢失*/if(p.count(i)) continue;//判断合法w[dep]=i;//记录路径long long xa=a*i-b,xb=i*b;//通分
//        long long z=gcd(xa,xb);dfs(dep+1,xa,xb,i+1);//i改变因为i是递增的}
}
int main()
{cin>>t;for(long long i=1;i<=t;i++){flag=0; mxdep=1;cin>>A>>B>>n;long long c;p.clear();//细节while(n--) scanf("%lld",&c),p.insert(c);//存储不合法的数while(mxdep++)//分裂成k个数就可以找到答案,从2开始{memset(ans,0,sizeof(ans));dfs(1,A,B,B/A+1);if(flag) break;}//迭代加深printf("Case %lld: %lld/%lld=1/%lld",i,A,B,ans[1]);for(int i=2;i<=mxdep;i++)printf("+1/%lld",ans[i]);printf("\n");}return 0;
}

例题7-10 UVa11212

什么IDA算法了,过

第八讲——高效算法设计

what??????????????

第九讲——动态规划初步

9.1 数字三角形

9.1.1数字三角形

数字三角形

标准的动态规划,容易实现

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
using namespace std;
#define mid 1000000007
int a,ans[102][102],c[102][102];
int sou(int x,int y){if(x==a){//最后一层 return ans[x][y]=c[x][y];}else{if(ans[x][y]!=0)return ans[x][y];else{return ans[x][y]=c[x][y]+max(sou(x+1,y),sou(x+1,y+1));}}
}
int main(){cin>>a;for(int i=1;i<=a;i++){for(int j=1;j<=i;j++){cin>>c[i][j];}}cout<<sou(1,1);
}

9.2 DAG上的动态规划

9.2.1DAG模型

矩形嵌套问题

有向无环图,不清楚DAG的可以博客查一下
感觉和上一道数字三角形差不多
就是
1.记忆化
2.建立有向图
3.保证每个点都有ans值
4.详细的写在代码里了

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
using namespace std;
#define mid 1000000007
//有向无环图
int b,ans[1006],xian[1006][1006],c[1006][2];
int dp(int a){int i,maxmax;if(ans[a]>0)return ans[a];//记忆化 maxmax=1;//注意初值设置为1 for(i=1;i<=b;i++){if(xian[a][i])//如果有向边存在 maxmax=max(dp(i)+1,maxmax);}return ans[a]=maxmax;
}
int main(){int a,maxmax,i,j;cin>>a;while(a--){memset(ans,0,sizeof(ans));memset(xian,0,sizeof(xian)); cin>>b;for(i=1;i<=b;i++)cin>>c[i][0]>>c[i][1];//建立有向图for(i=1;i<=b;i++){for(j=1;j<=b;j++){if((c[i][0]>c[j][0]&&c[i][1]>c[j][1])||(c[i][1]>c[j][0]&&c[i][0]>c[j][1])){xian[i][j]=1;//注意是j可以放在i里面 }}}maxmax=-1;//注意下面这样做的理由是//让每一个点肯定都会得到ans for(i=1;i<=b;i++){maxmax=max(maxmax,dp(i));//找出最大的那个ans }cout<<maxmax<<endl;}return 0;
}

硬币问题

这题我都找了好久

不用引用也能错?我吐了
代码是我网上cv的,我的有个样例超时,恶心死我

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <set>
using namespace std;
const int k = 0x3f3f3f3f;//最大最小值
int ans[10006], c[106], book[10006], a, b;//book数组用来记忆化
int da(int x) {if (book[x])return ans[x];book[x] = 1;int &maxmax = ans[x];//不用引用就完蛋maxmax = -k;for (int i = 1; i <= a; i++) {if (x >= c[i]) {maxmax = max(maxmax, da(x - c[i]) + 1);}}return ans[x] = maxmax;
}
int xiao(int x) {if (book[x])return ans[x];book[x] = 1;int &minmin = ans[x];minmin = k;for (int i = 1; i <= a; i++) {if (x >= c[i]) {minmin = min(minmin, xiao(x - c[i]) + 1);}}return minmin;
}
int main() {cin >> a >> b;for (int i = 1; i <= a; i++) {cin >> c[i];}book[0] = 1;ans[0] = 0;cout << xiao(b);memset(book, 0, sizeof(book));book[0] = 1;ans[0] = 0;cout << " " << da(b);
}

9.2.4 小结与应用举例

例题9.2 巴比伦塔

和前面的矩形嵌套大同小异

每个立方体产生三种摆放情况,然后就是标准的记忆化搜索


struct www{int x;int y;int z;
}c[200];//结构体储存每种摆放方式int ans[200],a;int dp(int p){//标准的记忆化搜索int i,maxmax;if(ans[p]){return ans[p];}maxmax=c[p].z;/*记住初始值设置为自己的长度,最短就是没有可以放在上面的,最小值就是自己*/for(i=1;i<=a*3;i++){if((c[i].x<c[p].x&&c[i].y<c[p].y)||(c[i].x<c[p].y&&c[i].y<c[p].x)){maxmax=max(maxmax,dp(i)+c[p].z);}}return ans[p]=maxmax;
}int main(){int i,p,e,f,g,k=0;while(scanf("%d",&a)&&a){p=0;memset(ans,0,sizeof(ans));for(i=1;i<=a;i++){cin>>e>>f>>g;c[++p].x=e,c[p].y=f,c[p].z=g;c[++p].x=f,c[p].y=g,c[p].z=e;c[++p].x=g,c[p].y=e,c[p].z=f;//每个立方体三种摆放方式 }int maxmax=0;for(i=1;i<=a*3;i++){maxmax=max(dp(i),maxmax);}cout<<"Case "<<++k<<": maximum height = "<<maxmax<<endl;}return 0;
}

9.3 多阶段决策问题

9.3.1 多段图的最短路

例题9.4 单项TSP

就是一个DP
注意细节的处理
代码又是一直WA

9.3.2 0-1背包问题

物品无限的背包问题(完全背包)

带权值的dp?就是以前dp的+1变成了+实质的值

int c[103][2], a, b;
int dp[50006];
int sou(int x);
int main() {memset(dp, -1, sizeof(dp));cin >> a >> b;for (int i = 0; i < a; i++) {cin >> c[i][0] >> c[i][1];}cout<<sou(b);return 0;
}
int sou(int x) {if (dp[x] != -1)return dp[x];int maxmax = 0;for (int i = 0; i < a; i++) {if (x >= c[i][0]) {maxmax = max(maxmax, c[i][1] + sou(x - c[i][0]));}}return dp[x] = maxmax;//记忆化
}

0-1背包问题

典型的0-1背包
代码是看了别人的,感觉还是没法独立写出来

int a, b, c[101][2],ans[10006];
int main() {cin >> a >> b;for (int i = 1; i <= a; i++) {cin >> c[i][0] >> c[i][1];}for (int i = 1; i <= a; i++) {for (int j = b; j >=c[i][0]; j--) {//保证可以往包里拿ans[j] = max(ans[j],ans[j-c[i][0]]+c[i][1]);//加上前面的效果}}cout << ans[b];
}

例题9.5 劲歌金曲

可算AC了

也算典型的01背包问题了,时间其实最大是有范围的。
注意最后要留一秒才能唱金曲,详细解释写在代码里了

#include<iostream>
#include<set>
#include<cstring>
#include<algorithm>
#include<string>
#include<stack>
#include<vector>
using namespace std;
//01背包
int k[52];
int ans[10000];//时间是有范围的
int main() {int a, b, c, z = 0;//z是输出时用的cin >> a;while (a--) {memset(ans, -1, sizeof(ans));cin >> b >> c;for (int j = 1; j <= b; j++) {cin >> k[j];}//平凡的输入ans[0] = 0;for (int i = 1; i <= b; i++) {//物品for (int j = c; j >=k[i]; j--) {//时间if (ans[j-k[i]] != -1)//确保j-k[i]在这个时间唱歌有可能实现ans[j] = max(ans[j], ans[j - k[i]] + 1);}}int maxmax = -1, p ;for (int i = 0; i < c; i++) {//等于c的情况特殊处理,因为c时无法唱《金曲》if (ans[i] >=maxmax) {//找最大的ans,并且时间i也要大的,所以有等号maxmax = ans[i];p = i;}}if (maxmax + 1 > ans[c] || (maxmax + 1 == ans[c]&&p+678>c))//条件判断printf("Case %d: %d %d\n", ++z, maxmax + 1, p + 678);elseprintf("Case %d: %d %d\n", ++z, ans[c], c);}return 0;
}

9.4 更多经典模型

9.4.1 线性结构上的动态规划

9.4.1 最长上升自序列(LIS)

只写了最智障的写法,其他的还不懂,后面再来

//最智障的n^2
int dp[1006],c[1006];
int main() {int a;cin >> a;for (int i = 1; i <= a; i++) {cin >> c[i];dp[i] = 1;}for (int i = 1; i <= a; i++) {for (int j = 1; j < i; j++) {if (c[i] > c[j]) {//比前面的数大,才可能形成上升序列dp[i] = max(dp[i], dp[j] + 1);/*表示以i结尾的最长上升序列,所以后面还有个遍历寻找最大*/}}}int ans = 0;for (int i = 0; i <= a; i++) {ans = max(ans, dp[i]);}cout << ans;return 0;
}

连环大跳(跳了很多)

第十讲——数据结构基础

10.1 数论初步

10.1.1 欧几里得算法和唯一分解定理

紫薯总览——AC代码+小题解相关推荐

  1. 【蓝桥系列】——十三届蓝桥杯PythonB组第五题E题蜂巢(AC代码)

    大家好,我是普通小明,初入学习博客,一起加油! 首先,感谢 小蓝刷题 对我的鼓励,我也希望加入学习算法这个大家庭. 第一篇文章,有些不完美,还请多多指教. 目录 (好像我并不会用锚点T-T) 省赛心得 ...

  2. 紫薯第10章数学 kaungbin专题14数论基础

    杂谈 kuangbin14数论Harmonic Number LightOJ - 1234 分段打表 + 欧拉爷爷o(1).(第一次触及了欧拉常熟) 10.1.1 && 10.1.2 ...

  3. POJ - 2392 朴素多重背包 + 贪心 WA与AC代码细节分析

    我们先来看下普通的朴素多重背包(拆成01背包求解) n种物品,背包大小w,每种物品重量 wi,价值 vi,个数 ci dp[j] 表示 大小为 j 的背包含有的最大价值,即 物品重量和 小于等于 j ...

  4. 例题6-18 UVA12171 Sculpture(90行AC代码)

    紫书刷题进行中,题解系列[GitHub|CSDN] 例题6-18 UVA12171 Sculpture(90行AC代码) 题目大意 给定笛卡尔坐标系上的长方体左下角坐标和对应边长,长方体间存在相离,相 ...

  5. 例题4-6 UVA12412 师兄帮帮忙(156行AC代码)

    紫书刷题进行中,题解系列点这里 例题4-6 UVA12412 师兄帮帮忙 思路分析 只需按部就班实现各个功能,虽然繁琐,但无难点.深入思考有助于提高编程能力. 虽实现容易,但新手和老手在效率和代码长度 ...

  6. 【算法设计与分析】经典常考三十三道例题AC代码

    ❥小虾目前大三,我校在大一下开设<数据结构>这门课,大二上开了<算法设计与分析>这门课,很庆幸这两门课的上机考试总成绩一门100,一门99,最后总分也都90+.下文会给出机试的 ...

  7. PAT Basic Level 1027 打印沙漏 解题思路及AC代码

    PAT 乙级 1027 打印沙漏 v1.0 1. 题目简述及在线测试位置 2. 基本思路 3. 完整AC代码 1. 题目简述及在线测试位置 1.1 给定N个字符,要求使用尽可能多的字符打印出一个沙漏. ...

  8. 2019 北邮计算机学院机试 附AC代码以及结果统计

    今年计院题目可能比网研难度大一些,没有AK,13人3A,57人2A,98人1A,24人0A 给大家趁热回忆一下题目. 以下题目为回忆版,有些数据细节记不起来了 Problem A 二进制 时间限制 1 ...

  9. 养生之道——》五红汤、紫薯枸杞银耳汤、山楂红枣红糖水、大枣红糖姜水、红薯汤

    版权声明:本文为博主原创文章,无需授权即可转载,甚至无需保留以上版权声明,转载时请务必注明作者. https://blog.csdn.net/weixin_43453386/article/detai ...

最新文章

  1. SpringCloud 2020版本教程4:使用spring cloud sleuth+zipkin实现链路追踪
  2. mongodb 对象唯一索引_什么是MongoDB?简介,架构,功能和示例
  3. Linux 文本界面转到图形界面
  4. 在c语言中scanf什么时候用,scanf什么时候用??c语言?
  5. 【C语言简单说】二十一:双重指针基础 (完结)
  6. 使用标准库函数对象的例子
  7. 敬伟PS教程:掌握篇B07高级抠图
  8. Unity_Demo | 中世纪风3D-RPG游戏
  9. 100流明相当于多少w_lx和瓦数换算(1lx等于多少w)
  10. 日语 数字 时间 星期 月日 读法总结
  11. Ubuntu中解压缩命令
  12. 数列求和-加强版(C语言)
  13. 做计算机项目的流程图,软件工程实验三(程序流程图和PAD图)
  14. 后台集成解决方案 avue
  15. maya(学习笔记)之Arnold渲染器二
  16. Java中一次对象的自我拯救探究
  17. java 视频流 读取_Java之视频读取IO流解帧实施方案
  18. nist是什么软件_NIST推荐什么
  19. 趣味测试小程序源码带流量主广告位开源小程序
  20. React 大数据可视化(大屏展示)解决方案

热门文章

  1. 如何用python制作成绩单生成器【安城安教具】-【其它】-【成绩单生成器】
  2. DBCO-amine Cas:1255942-06-3,DBCO-NH2,二苯基环辛炔-氨基可衍生DBCO-PEG-NH2
  3. 前向传播和反向传播(举例说明)
  4. JArray的使用以及动态获取对象属性值
  5. 手机计算机隐藏功能怎么关闭,手机计算机自带的隐藏功能,我也是现在才知道,功能比你想得多...
  6. 城市生命线安全风险综合监测预警解决方案
  7. OTP概念及实现原理简析 安当加密
  8. 从《学术津梁》看草书创作轨程
  9. MySQL查每周、每月、每年、每天数据
  10. php的封装construct构造方法,__construct() 构造函数