C与C++ 算法笔记中的代码

2 篇文章 0 订阅

EOF使用:
MAC系统:输入结束后需要—>回车键—>(control+D)。即可结束输入。
windows系统:输入结束后需要—>回车键—>(control+Z)—>回车键

C++ 这里的 = 拷贝是值拷贝,会得到一个新的数组

class Solution {
public:
    void rotate(vector<vector<int>>& matrix) {
        int n = matrix.size();
        // C++ 这里的 = 拷贝是值拷贝,会得到一个新的数组
        auto matrix_new = matrix;
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                matrix_new[j][n - i - 1] = matrix[i][j];
            }
        }
        // 这里也是值拷贝
        matrix = matrix_new;
    }
};

begin()函数和end()位于iteartor;
而front()和back()位于vector list deque and etc…

#include <iostream>  
#include <vector>  
using namespace std;  
int main()  
{  
    vector<char> v1;  
    vector<char>::iterator iter1;  
    vector<char>::iterator iter2;  
    v1.push_back('a');  
    v1.push_back('b');  
    v1.push_back('c');  
    v1.push_back('d');  

    cout << "v1.front() = " << v1.front() << endl;  
    cout << "v1.back() = " << v1.back() << endl;  

    iter1 = v1.begin();  
    cout << *iter1 << endl;  
    iter2 = v1.end()-1; 
    //v1.end()指向的是最后一个元素的下一个位置,所以访问最后一个元素,所以:iter2 = v1.end() - 1 是使iter2指向最后一个元素 
    cout << *iter2 << endl;  
    return 0;  
}  

C++ 标准模版库STL

除开vector和string之外的STL容器都不支持*(it+i)的访问方式
vector:向量/变长数组

Vector<类型>标识符(最大容量,初始所有值)
以及vector< vector<int> > dp(m, vector<int>(n) )

常见定义方法:(1) vector<int> a(5); //定义了5个整型元素的向量(<>中为元素类型名,它可以是任何合法的数据类型),但没有给出初值,其值是不确定的。
   (2)vector<int> a(5,1); //定义了5个整型元素的向量,且给出每个元素的初值为1
   (3)vector<int> a(b); //用b向量来创建a向量,整体复制性赋值
   (4)vector<int> a(b.begin(),b.begin+3); //定义了a值为b中第0个到第2个(共3个)元素
   (5)int b[7]={1,2,3,4,5,9,8};
          vector<int> a(b,b+7); //从数组中获得初值
 

vector< vector<int> > v(m, vector<int>(n) );定义了一个vector容器,元素类型为vector<int>,初始化为包含m个vector<int>对象,每个对象都是一个新创立的vector<int>对象的拷贝,而这个新创立的vector<int>对象被初始化为包含n个0。
#include<vector>
using namespace std;
定义:
	vector<int> name;
	vector<int> vi[100];
	vector<vector<int> > name;
访问:
	下标 vi[index]
	迭代器 vector<int>::iterator it = vi.begin();
			通过*it来访问vector里的元素
函数:
	push_back()
	pop_back()
	size()
	clear()
	insert(it,x)
	erase()

set:集合 内部自动有序且不含重复元素

#include<set>
using namespace std;
定义:
	set<int> name;
访问:
	迭代器 set<int>::iterator it;
		  通过*it来访问set里的元素
函数:
	insert()
	find(value) 返回set中对应值为value的迭代器
	erase()
	size()
	clear()

string字符串:

#include<string>
using namespace std;
定义: string str;
访问:
	下标:str[i]
			   如果要读入和输出整个字符串,则只能用cin和cout
	迭代器: string::iterator it;
函数:
	operator+=
		str1+=str2;	//将str2直接拼接到str1上
	length()/size()
	insert()
	erase()
	clear()
	substr()
	string::npos:-1
	find()
	replace()

map映射:map会以键从小到大的顺序自动排序,map的键和值是唯一的

#include<map>
using namespace std;
定义:
	map<string,int> mp;
访问:
	下标:mp['c']
	迭代器 map<char,int>::iterator it;
		  通过 it->first 来访问键 it->second来访问值
函数:
	find(key) 返回键为key的映射的迭代器
	erase()
	size()
	clear()

queue 队列:

#include<queue>
using namespace std;
queue<int> q;
push()  pop()
front()  back()
empty()
size()

priority_queue 优先队列:队首元素优先级最大

#include<queue>
using namespace std;
priority_queue<int> q;
push()  pop()
top()
empty()
size()
priority_queue<int,vector<int>,greater<int> >q;	//最小的元素放在队首
struct fruit{
	string name;
	int price;
	friend bool operator < (fruit f2,fruit f2){
		return f1.price > f2.price;
	}
};

stack 栈:

#include<stack>
using namespace std;
stack<int> st;
push()  pop()
top()
empty()
size()

pair 一个内部有两个元素的结构体:

#include<utility>
using namespace std;

algorithm:

**sort(首元素地址,尾元素地址的下一个地址,cmp比较函数):**
#include<algorithm>
using namespace std;
在STL标准容器中,只有 vector向量、string字符串、deque队列 是可以使用sort的
**#include <numeric>:**
accumulate(a,b,c)累加求和:
a为起始地址,b为结束地址,c为初始值
#include <numeric>
vector<int> v={1,2,3,4};
int sum = accumulate(v.begin(),v.end(),0);

C++和C:

C++中有string类型;len=str.length()
C语言中没有单独一种基本数据类型可以存储字符串,只能使用字符数组的方式。(字符串常量可以作为初值赋给字符数组,并使用%s的格式输出);len=strlen(str)
char str[4]=“abcd”;
printf("%s",str);

C++可以直接使用布尔型
C语言中必须添加stdbool.h头文件才可以使用

C语言中不允许在for语句的表达式A里定义变量;
C++中可以
for(int i=1;i<=100;i++){
sum=sum+i;
}

C++:
引用:对引用变量的操作就是对原变量的操作(引用不是取地址)
void change(int &x){
x=1;
}

C:malloc free
C++:new delete
C++:

头文件:

#include<stdio.h> #include(C++)
输入:
scanf("%d",&n);
scanf("%lld",&n); //long long
scanf("%s",str);
scanf("%f",&f); //float
scanf("%lf",&db); //double
输出:
printf("%d",n);
printf("%lld",n); //long long
printf("%f",fl); //float
printf("%f",db); //double
sscanf(str,"%d",&n):把字符数组str中的内容以"%d"的格式写到n中
sprintf(str,"%d",n):把n以"%d"的格式写到str字符数组中

%f是float和double型的输出格式
转义字符:\n \t \0
a^b:位异或

scanf("%s",str);
printf("%s",str);
getchar():输入单个字符,可以识别换行符
putchar():输出单个字符
gets():输入一行字符串
puts():输出一行字符串
注:
scanf输入时:
%c格式能识别空格跟换行并将其输入;
%s通过空格或换行来识别一个字符串的结束
gets()识别换行符\n作为输入结束

注释:/* */ 或 //

math函数
#include<math.h>
fabs(double x):取绝对值
floor(double x):向下取整
ceil(double x):向上取整
pow(double x,double y):x^y
sqrt(double x):算术平方根
log(double x):以自然对数e为底的对数
round(double x):四舍五入,返回类型也是double型,需进行取整

const double pi=acos(-1.0);

#include<string.h>
memset(a,0,sizeof(a)); //赋值0或-1
strlen(str):长度
strcmp():返回两个字符串大小的比较结果
strcpy():复制
strcat():连接

生成随机数据:P144
[a,b]:rand()%(b-a+1)+a
[a,b],b>RAND_MAX:(int)round(1.0rand()/RAND_MAX(b-a)+a)

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main(){
    srand((unsigned)time(NULL));
    for(int i=0;i<10;i++){
        printf("%d ",(int)(round(1.0*rand()/RAND_MAX*50+10)));  //随机数[10,60]
    } 
    return 0;
}

switch语句
switch(表达式){
case 常量表达式1:
……
break;
case 常量表达式n:
……
break;
default:
……
}

数组:
一维数组:
int a[10]={5,3,2,6,8,4};
int a[10]={} //都赋初值0
数组作为函数参数时:
参数中数组的第一维不需要填写长度(如果是二维数组,那么第二维需要填写长度),实际调用时也只需填写数组名;
在函数中对数组元素的修改就等同于是对原数组元素的修改(这与普通的局部变量不同)P59

指针:
指针指向内存地址
只要在变量前面加上&,就表示变量的地址
指针变量用来存放指针
数组的名称作为数组的首地址使用 a==&a[0]
a+i==&a[i] *(a+i)==a[i]
两个int型的指针相减,等价于在求两个指针之间相差了几个int

int a;
int* p=&a; //地址&a赋值给p,*p获得a的值

结构体:

struct studentInfo{
	int id;
	char name[20];
	studentInfo *next;
}stu,*p;
//访问变量
stu.id
p->id
#include<stdio.h>
struct Point{
    int x,y;
    Point(){}       //用以不经初始化地定义pt[10]
    Point(int _x,int _y):x(_x),y(_y){}  //用以提供x和y的初始化
}pt[10];

int main(){
    int num=0;
    for(int i=1;i<=3;i++){
        for(int j=1;j<=3;j++){
            pt[num++]=Point(i,j);   //直接使用构造函数
        }
    }
    for(int i=0;i<num;i++){
        printf("%d,%d\n",pt[i].x,pt[i].y);
    }
    return 0;
}

代码实例

简单:

//PAT B1032 挖掘机技术哪家强 P86
#include<stdio.h>
const int maxn=100010;
int school[maxn]={0};
int main(){
    int n,schID,score;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d %d",&schID,&score);
        school[schID]+=score;
    }
    int k=1,MAX=-1;
    for(int i=1;i<=n;i++){
        if(school[i]>MAX){
            MAX=school[i];
            k=i;
        }
    }
    printf("%d %d\n",k,MAX);
    return 0;
}

中等:

//冒泡排序
#include<stdio.h>
int main(){
    int a[10]={3,1,4,5,2};
    for(int i=1;i<=4;i++){   //循环4次
        for(int j=0;j<5-i;j++){
            if(a[j]>a[j+1]){
                int temp=a[j];
                a[j]=a[j+1];
                a[j+1]=temp;
            }
        }
    }
    for(int k=0;k<5;k++){
        printf("%d ",a[k]);
    }
    return 0;
}
//PAT B1020 月饼 P118
#include<stdio.h>
#include<algorithm>
using namespace std;
struct mooncake{
    double store;       //库存量
    double sell;        //总售价
    double price;       //单价
}cake[1010];
bool cmp(mooncake a,mooncake b){        //按单价从高到低排序
    return a.price>b.price;
}
int main(){
    int n;
    double D;
    scanf("%d%lf",&n,&D);
    for(int i=0;i<n;i++){
        scanf("%lf",&cake[i].store);
    }
    for(int i=0;i<n;i++){
        scanf("%lf",&cake[i].sell);
        cake[i].price=cake[i].sell/cake[i].store;       //计算单价
    }
    sort(cake,cake+n,cmp);  //按单价从高到低排序
    double ans=0;           //收益
    for(int i=0;i<n;i++){
        if(cake[i].store<=D){   //如果需求量高于月饼库存量
            ans+=cake[i].sell;
            D-=cake[i].store;
        }else{                  //如果月饼库存量高于需求量
            ans+=D*cake[i].price;
            break;
        }
    }
    printf("%.2f\n",ans);
    return 0;
}
//PAT B1019/A1069 数字黑洞 P152
#include<stdio.h>
#include<algorithm>
using namespace std;
bool cmp(int a,int b){
    return a>b;
}
void to_array(int n,int num[]){     //将n中每一位存到num数组中
    for(int i=0;i<4;i++){
        num[i]=n%10;
        n=n/10;
    }
}
int to_number(int num[]){           //将num数组转换为数字
    int sum=0;
    for(int i=0;i<4;i++){
        sum=sum*10+num[i];
    }
    return sum;
}

int main(){
    int n,MIN,MAX;          //MIN和MAX分别表示递增排序和递减排序后得到的最小值和最大值
    scanf("%d",&n);
    int num[5];
    while(1){
        to_array(n,num);
        sort(num,num+4);
        MIN=to_number(num);
        sort(num,num+4,cmp);
        MAX=to_number(num);
        n=MAX-MIN;
        printf("%04d-%04d=%04d\n",MAX,MIN,n);
        if(n==0 || n==6174) break;      //退出
    }
    return 0;
}

复杂:

//日期差值P91
#include<stdio.h>
int month[13][2]={  //平年和闰年的每个月的天数
    {0,0},{31,31},{28,29},{31,31},{30,30},{31,31},{30,30},
          {31,31},{31,31},{30,30},{31,31},{30,30},{31,31}
};
bool isLeap(int year){  //判断是否是闰年
    return (year%4==0 && year%100!=0) || (year%400==0);
}
int main(){
    int time1,y1,m1,d1;
    int time2,y2,m2,d2;
    while(scanf("%d%d",&time1,&time2)!=EOF){
        if(time1>time2){    //第一个日期晚于第二个日期,则交换
            int temp=time1;
            time1=time2;
            time2=temp;
        }
        y1=time1/10000,m1=time1%10000/100,d1=time1%100;
        y2=time2/10000,m2=time2%10000/100,d2=time2%100;
        int ans=1;  //记录结果
        //第一个日期没有达到第二个日期时进行循环
        while(y1<y2||m1<m2||d1<d2){
            d1++;
            if(d1==month[m1][isLeap(y1)]+1){    //满当月天数
                m1++;
                d1=1;
            }
            if(m1==13){ //月份满12个月
                y1++;
                m1=1;
            }
            ans++;
        }
        printf("%d\n",ans);
    }
    return 0;
}
//PAT B1009 说反话 P97
#include<stdio.h>
int main(){
    int num=0;  //单词的个数
    char ans[90][90];
    while(scanf("%s",ans[num])!=EOF){   //一直输入直到文件末尾
        num++;  //单词个数加1
    }
    for(int i=num-1;i>=0;i--){  //倒着输出单词
        printf("%s",ans[i]);
        if(i>0) printf(" ");
    }
    return 0;
}

#include<iostream>
#include<string>
using namespace std;
int main(){
    string str;
    getline(cin,str,'\n');
//  char (*ans)[90]=(char(*)[90])malloc(sizeof(char)*90*90); 
//  cin>>str;
    int len=str.length(),r=0,h=0;    //r为行,h为列
    char ans[90][90]={};   //ans[0]~ans[r]存放单词
    for(int i=0;i<len;i++){
        if(str[i]!=' '){
            ans[r][h++]=str[i];
        }else{
            ans[r][h]='\0';
            r++;
            h=0;
        }
    }
    for(int i=r;i>=0;i--){
        cout<<ans[i];
        if(i>0) printf(" ");
    }
    return 0;
}
//PAT A1025 Ranking P103
#include<stdio.h>
#include<algorithm>
using namespace std;

struct Student{
    char id[15];    //准考证号
    int score;
    int location_number;    //考场号
    int local_rank; //考场内排名
}stu[30010];

bool cmp(Student a,Student b){
    if(a.score!=b.score) return a.score>b.score;
    else return strcmp(a.id,b.id)<0;
}

int main(){
    int n,k,num=0;  //num为总考生数
    scanf("%d",&n); //n为考场数
    for(int i=1;i<=n;i++){
        scanf("%d",&k);         //该考场内人数
        for(int j=0;j<k;j++){
            scanf("%s%d",stu[num].id,&stu[num].score);
            stu[num].location_number=i;
            num++;
        }
        sort(stu+num-k,stu+num,cmp);        //将该考场的考生排序
        stu[num-k].local_rank=1;
        for(int j=num-k+1;j<num;j++){
            if(stu[j].score==stu[j-1].score){
                stu[j].local_rank=stu[j-1].local_rank;
            }else{
                stu[j].local_rank=j-num+k+1;
            }
        }
    }
    printf("%d\n",num);             //输出总考生数
    sort(stu,stu+num,cmp);          //将所有考生排序
    int r=1;
    for(int i=0;i<num;i++){
        if(i>0 && stu[i].score!=stu[i-1].score){
            r=i+1;                  //当前考生与上一个考生分数不同时,让r更新为人数+1
        }
        printf("%s %d %d %d\n",stu[i].id,r,stu[i].location_number,stu[i].local_rank);
    }
    return 0;
}
//输出1~3的全排列
#include<stdio.h>
const int maxn=11;
//P为当前排列,hashTable记录整数x是否已经在P中
int n,P[maxn],hashTable[maxn]={false};
//当前处理排列的第index号位
void generateP(int index){
    if(index==n+1){                 //递归边界,已经处理完排列的1~n位
        for(int i=1;i<=n;i++){
            printf("%d ",P[i]);     //输出当前排列
        }
        printf("\n");
        return;
    }
    for(int x=1;x<=n;x++){          //枚举1~n,试图将x填入P[index]
        if(hashTable[x]==false){    //如果x不在P[0]~P[index-1]中
            P[index]=x;             //令P的第index位为x,即把x加入当前排列
            hashTable[x]=true;      //记x已在P中
            generateP(index+1);     //处理排列的第index+1号位
            hashTable[x]=false;     //已处理完P[index]为x的子问题,还原状态
        }
    }
}
int main(){
    n=3;                //欲输出1~3的全排列
    generateP(1);       //从P[1]开始填
    return 0;
}
//区间贪心 P122
#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxn=110;
struct Inteval{
    int x,y;        //开区间左右端点
}I[maxn];
bool cmp(Inteval a,Inteval b){
    if(a.x!=b.x) return a.x>b.x;    //先按左端点从大到小排序
    else return a.y<b.y;            //左端点相同的按右端点从小到大排序
}
int main(){
    int n;
    while(scanf("%d",&n),n!=0){
        for(int i=0;i<n;i++){
            scanf("%d%d",&I[i].x,&I[i].y);
        }
        sort(I,I+n,cmp);            //把区间排序
        int ans=1,lastX=I[0].x;
        for(int i=1;i<n;i++){
            if(I[i].y<=lastX){
                lastX=I[i].x;
                ans++;
            }
        }
        printf("%d\n",ans);
    }    
    return 0;
}
//PAT B1040/A1093 有几个PAT P147
#include<stdio.h>
#include<string.h>
const int MAXN=10010;
const int MOD=1000000007;
char str[MAXN];
int leftNumP[MAXN]={};      //每一位左边(含)P的个数
int main(){
    gets(str);
    int len=strlen(str);
    for(int i=0;i<len;i++){
        if(i>0) leftNumP[i]=leftNumP[i-1];
        if(str[i]=='P') leftNumP[i]++;
    }
    int ans=0,rightNumT=0;      //ans为答案,rightNumT记录右边T的个数
    for(int i=len-1;i>=0;i--){
        if(str[i]=='T') rightNumT++;
        else if(str[i]=='A') ans=(ans+leftNumP[i]*rightNumT)%MOD;
    }
    printf("%d\n",ans);
    return 0;
}
//PAT A1020 Tree Traversals P296
#include<stdio.h>
#include<queue>
using namespace std;
const int maxn=50;
struct node{
    int data;
    node* lchild;
    node* rchild;
};
int in[maxn],post[maxn];      //中序、后序
int n;      //结点个数

//返回构建出的二叉树的根结点地址
node* create(int postL,int postR,int inL,int inR){
    if(postL>postR) return NULL;
    node* root=new node;
    root->data=post[postR];
    int k;
    for(k=inL;k<=inR;k++){
        if(in[k]==post[postR]) break;
    }
    int numLeft=k-inL;
    root->lchild=create(postL,postL+numLeft-1,inL,k-1);
    root->rchild=create(postL+numLeft,postR-1,k+1,inR);
    return root;
}

int num=0;      //已输出的结点个数
void BFS(node* root){
    queue<node*> q;
    q.push(root);
    while(!q.empty()){
        node* now=q.front();
        q.pop();
        printf("%d",now->data);
        num++;
        if(num<n)   printf(" ");
        if(now->lchild != NULL) q.push(now->lchild);
        if(now->rchild != NULL) q.push(now->rchild);
    }
}

int main(){
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",&post[i]);
    }
    for(int i=0;i<n;i++){
        scanf("%d",&in[i]);
    }
    node* root=create(0,n-1,0,n-1); //建树
    BFS(root);                      //层序遍历
    return 0;
}
//PAT A1034 Head of a Gang P354
#include<iostream>
#include<map>
#include<string>
using namespace std;
const int maxn=2010;        //总人数

map<int,string> inToString;     //编号->姓名
map<string,int> stringToInt;    //姓名->编号
map<string,int> Gang;           //head->人数
int G[maxn][maxn]={0}, weight[maxn]={0};       //邻接矩阵G、点权 weight
int n,k,numPerson=0;        //边数n、下限k、总人数numPerson
bool vis[maxn]={false}; //标记是否被访问

//DFS函数访问单个连通块,nowVisit为当前访问的编号
//head为头目,numMember为成员编号,totalValue为连通块的总边权
void DFS(int nowVisit,int &head,int &numMember,int &totalValue){
    numMember++;        //成员人数加1
    vis[nowVisit]=true; //标记nowVisit已访问
    if(weight[nowVisit]>weight[head]){
        head=nowVisit;      //更新头目
    }
    for(int i=0;i<numPerson;i++){   //枚举所有人
        if(G[nowVisit][i]>0){
            totalValue+=G[nowVisit][i];
            G[nowVisit][i]=0;
            G[i][nowVisit]=0;
            if(vis[i]==false){
            DFS(i,head,numMember,totalValue);
            }
        }
    }
}

//DFSTrave函数遍历整张图,获取每个连通块的信息
void DFSTrave(){
    for(int i=0;i<numPerson;i++){
        if(vis[i]==false){
            int head=i,numMember=0,totalValue=0;    //头目,成员数,总边权
            DFS(i,head,numMember,totalValue);
            if(numMember>2 && totalValue>k){
                Gang[inToString[head]] = numMember;
            }
        }
    }
}

//change 函数返回姓名str对应的编号
int change(string str){
    if(stringToInt.find(str) != stringToInt.end())  return stringToInt[str];
    else{
        stringToInt[str]=numPerson;
        inToString[numPerson]=str;
        return numPerson++;
    }
}

int main(){
    int w;
    string str1,str2;
    cin >> n >> k;
    for(int i=0;i<n;i++){
        cin >> str1 >>str2 >> w;
        int id1=change(str1);
        int id2=change(str2);
        weight[id1]+=w;
        weight[id2]+=w;
        G[id1][id2]+=w;
        G[id2][id1]+=w;
    }
    DFSTrave();     //遍历整个图的所有连通块,获取Gang的信息
    cout << Gang.size() << endl;
    map<string,int>::iterator it;
    for(it=Gang.begin();it!=Gang.end();it++){
        cout << it->first << " " << it->second << endl;
    }
    return 0;
}
//PAT A1076 Forwards on Weibo
#include<stdio.h>
#include<string.h>
#include<queue>
#include<vector>
using namespace std;
const int maxn=1010;
struct Node{
    int id;
    int layer;
};
vector<Node> Adj[maxn];     //邻接表
bool inq[maxn]={false};     //顶点是否已被加入过队列

int BFS(int s,int L){       //start为起始结点,L为层数上限
    int numForward=0;       //转发数
    queue<Node> q;
    Node start;
    start.id=s;
    start.layer=0;
    q.push(start);
    inq[start.id]=true;
    while(!q.empty()){
        Node topNode=q.front();
        q.pop();
        int u=topNode.id;
        for(int i=0;i<Adj[u].size();i++){
            Node next=Adj[u][i];
            next.layer=topNode.layer+1;
            if(inq[next.id]==false && next.layer<=L){
                q.push(next);
                numForward++;
                inq[next.id]=true;
            }
        }
    }
    return numForward;
}

int main(){
    Node user;
    int n,L,numFollow,idFollow;
    scanf("%d%d",&n,&L);            //结点个数,层数上限
    for(int i=1;i<=n;i++){
        user.id=i;
        scanf("%d",&numFollow);
        for(int j=0;j<numFollow;j++){
            scanf("%d",&idFollow);
            Adj[idFollow].push_back(user); //边idFollow->i
        }
    }
    int numQuery,s;
    scanf("%d",&numQuery);      //查询个数
    for(int i=0;i<numQuery;i++){
        memset(inq,false,sizeof(inq));      //inq数组初始化
        scanf("%d",&s); //起始结点编号
        int numForward = BFS(s,L);
        printf("%d\n",numForward);
    }
    return 0;
}
//PAT A1030 Travel Plan P385
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxn=510;
const int INF=1000000000;

int n,m,st,ed,G[maxn][maxn],cost[maxn][maxn];
int d[maxn],c[maxn],pre[maxn];
bool vis[maxn]={false};

void Dijkstra(int s){
    fill(d,d+maxn,INF);
    fill(c,c+maxn,INF);
    for(int i=0;i<n;i++) pre[i]=i;
    d[s]=0;
    c[s]=0;
    for(int i=0;i<n;i++){       //循环n次
        int u=-1,MIN=INF;
        for(int j=0;j<n;j++){   //找到未访问的顶点中d[]最小的
            if(vis[j]==false && d[j]<MIN){
                u=j;
                MIN=d[j];
            }
        }
        //找不到小于INF的d[u],说明剩下的顶点和起点不连通
        if(u==-1) return;
        vis[u]=true;
        for(int v=0;v<n;v++){
            if(vis[v]==false && G[u][v]!=INF){
                if(d[u]+G[u][v]<d[v]){
                    d[v]=d[u]+G[u][v];
                    c[v]=c[u]+cost[u][v];
                    pre[v]=u;
                }else if(d[u]+G[u][v]==d[v]){
                    if(c[u]+cost[u][v]<c[v]){
                        c[v]=c[u]+cost[u][v];
                        pre[v]=u;
                    }
                }
            }
        }
    }
}

void DFS(int v){
    if(v==st){
        printf("%d ",v); 
        return;
    }
    DFS(pre[v]);
    printf("%d ",v); 
}

int main(){
    scanf("%d%d%d%d",&n,&m,&st,&ed);
    int u,v;
    fill(G[0],G[0]+maxn*maxn,INF);
    for(int i=0;i<m;i++){
        scanf("%d%d",&u,&v);
        scanf("%d%d",&G[u][v],&cost[u][v]);
        G[v][u]=G[u][v];
        cost[v][u]=cost[u][v];
    }
    Dijkstra(st);
    DFS(ed);
    printf("%d %d\n",d[ed],c[ed]);
    return 0;
}

动态规划

//斐波那契数列 P425
#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxn=1010;
int dp[maxn];
int F(int n){
    if(n==0 || n==1) return 1;
    if(dp[n]!=-1) return dp[n];
    else{
        dp[n]=F(n-1)+F(n-2);
        return dp[n];
    }

}

int main(){
    fill(dp,dp+maxn,-1);
    int n;
    scanf("%d",&n);
    printf("%d",F(n));
    return 0;
}
//数塔问题 P426
#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxn=1010;
int dp[maxn][maxn],f[maxn][maxn];
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=i;j++){
            scanf("%d",&f[i][j]);       //输入数塔
        }
    }
    //边界
    for(int j=1;j<=n;j++){
        dp[n][j]=f[n][j];
    }
    //从第n-1层不断向上计算出dp[i][j]
    for(int i=n-1;i>=1;i--){
        for(int j=1;j<=i;j++){
            //状态转移方程
            dp[i][j]=max(dp[i+1][j],dp[i+1][j+1])+f[i][j];
        }
    }
    printf("%d",dp[1][1]);
    return 0;
}
//最大连续子序列和 P429
#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxn=10010;
int dp[maxn],A[maxn];   //A[i]存放序列,dp[i]存放A[i]结尾的连续序列的最大和
int main(){
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++){       //读入序列
        scanf("%d",&A[i]);
    }
    //边界
    dp[0]=A[0];
    for(int i=1;i<n;i++){
        //状态转移方程
        dp[i]=max(dp[i-1]+A[i],A[i]);
    }
    int k=0;
    for(int i=1;i<n;i++){
        if(dp[i]>dp[k]){
            k=i;
        }
    }
    printf("%d\n",dp[k]);
    return 0;
}
//A1007 Maximum Subsequence Sum PP387
#include<stdio.h>
const int maxn=10010;
int dp[maxn],A[maxn];   //A[i]存放序列,dp[i]存放A[i]结尾的连续序列的最大和
int s[maxn]={0};        //s[i]表示产生dp[i]的连续序列从A的哪一个元素开始
int main(){
    int n;
    bool flag=false;    //false表示数组A中全小于0
    scanf("%d",&n);
    for(int i=0;i<n;i++){       //读入序列
        scanf("%d",&A[i]);
        if(A[i]>=0) flag=true;
    }
    if(flag==false){
        printf("0 %d %d",A[0],A[n-1]);
        return 0;
    }
    //边界
    dp[0]=A[0];
    for(int i=1;i<n;i++){
        //状态转移方程
        if(dp[i-1]+A[i] >= A[i]){
            dp[i]=dp[i-1]+A[i];
            s[i]=s[i-1];
        }else{
            dp[i]=A[i];
            s[i]=i;
        }
    }
    int k=0;
    for(int i=1;i<n;i++){
        if(dp[i]>dp[k]){
            k=i;
        }
    }
    printf("%d %d %d\n",dp[k],A[s[k]],A[k]);
    return 0;
}
//最长不下降子序列(LIS) P432
#include<stdio.h>
#include<algorithm>
using namespace std;
const int N=100;
int A[N],dp[N];
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&A[i]);
    }
    int ans=-1;
    for(int i=1;i<=n;i++){
        dp[i]=1;
        for(int j=1;j<i;j++){
            if(A[j]<=A[i] && dp[j]+1>dp[i]){
                dp[i]=dp[j]+1;
            }
        }
        ans=max(ans,dp[i]);
    }
    printf("%d\n",ans);
    return 0;
}
//A1045 Favorite Color Stripe PP390
#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxc=210; //最大颜色数
const int maxn=10010;   //最大L
int HashTable[maxc];    //将喜欢的颜色序列映射为递增序列,不喜欢的映射为-1
int A[maxn],dp[maxn];

int main(){
    int n,m,x;
    scanf("%d%d",&n,&m);
    fill(HashTable,HashTable+maxc,-1);
    for(int i=0;i<m;i++){
        scanf("%d",&x);
        HashTable[x]=i;
    }
    int L,num=0;
    scanf("%d",&L);
    for(int i=0;i<L;i++){
        scanf("%d",&x);
        if(HashTable[x]>=0){
            A[num++]=HashTable[x];
        }
    }
    int ans=-1;
    for(int i=0;i<num;i++){
        dp[i]=1;
        for(int j=0;j<i;j++){
            if(A[j]<=A[i] && dp[i]<dp[j]+1){
                dp[i]=dp[j]+1;
            }
        }
        ans=max(ans,dp[i]);
    }
    printf("%d\n",ans);
    return 0;
}
//6
//5 2 3 1 5 6
//12 2 2 4 1 5 5 6 3 1 1 5 6
7
//最长公共子序列(LCS) P434
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int N=100;
char A[N],B[N];
int dp[N][N];

int main(){
    gets(A+1);      //从下标为1开始读入
    gets(B+1);
    int lenA=strlen(A+1);
    int lenB=strlen(B+1);
    //边界
    for(int i=0;i<=lenA;i++){
        dp[i][0]=0;
    }
    for(int j=0;j<=lenB;j++){
        dp[0][j]=0;
    }
    //状态转移方程
    for(int i=1;i<=lenA;i++){
        for(int j=1;j<=lenB;j++){
            if(A[i]==B[j]){
                dp[i][j]=dp[i-1][j-1]+1;
            }else{
                dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
            }
        }
    }
    printf("%d\n",dp[lenA][lenB]);
    return 0;
}
//sadstory
//adminisorry
6
//A1045 Favorite Color Stripe PP392
#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxc=210; //最大颜色数
const int maxn=10010;   //最大L
int A[maxc],B[maxn],dp[maxc][maxn];

int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d",&A[i]);
    }
    int L;
    scanf("%d",&L);
    for(int i=1;i<=L;i++){
        scanf("%d",&B[i]);
    }
    //边界
    for(int i=0;i<=m;i++){
        dp[i][0]=0;
    }
    for(int j=0;j<=L;j++){
        dp[0][j]=0;
    }
    //状态转移方程
    for(int i=1;i<=m;i++){
        for(int j=1;j<=L;j++){
            int MAX=max(dp[i-1][j],dp[i][j-1]);
            if(A[i]==B[j]){
                dp[i][j]=MAX+1;
            }else{
                dp[i][j]=MAX;
            }
        }
    }
    printf("%d\n",dp[m][L]);
    return 0;
}
//6
//5 2 3 1 5 6
//12 2 2 4 1 5 5 6 3 1 1 5 6
7
//A1040 Longest Symmetric String(最长回文子串) P394
#include<stdio.h>
#include<string.h>
const int maxn=1010;
char S[maxn];
int dp[maxn][maxn];
int main(){
    gets(S);
    int len=strlen(S),ans=1;        //ans为最长回文子串的长度
    memset(dp,0,sizeof(dp));
    //边界
    for(int i=0;i<len;i++){
        dp[i][i]=1;
        if(i<len-1){
            if(S[i]==S[i+1]){
                dp[i][i+1]=1;
                ans=2;
            }         
        }
    }
    //状态转移方程
    for(int L=3;L<=len;L++){        //枚举子串的长度
        for(int i=0;i+L-1<len;i++){ //枚举子串的起始端点
            int j=i+L-1;            //子串的右端点
            if(S[i]==S[j] && dp[i+1][j-1]==1){
                dp[i][j]=1;
                ans=L;
            }
        }
    }
    printf("%d\n",ans);
    return 0;    
}
//Is PAT&TAP symmetric?
11
//A1068 Find More Coins(背包问题) PP396
#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxn=10010;
const int maxv=110;
int w[maxn],dp[maxv];
int choice[maxn][maxv];
int flag[maxn];
bool cmp(int a,int b){
    return a>b;
}
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&w[i]);
    }
    sort(w+1,w+n+1,cmp);        //逆序排列
    //边界
    for(int i=0;i<=m;i++){
        dp[i]=0;
    }
    //状态转移方程
    for(int i=1;i<=n;i++){
        for(int v=m;v>=w[i];v--){
            if(dp[v]<=dp[v-w[i]]+w[i]){
                dp[v]=dp[v-w[i]]+w[i];
                choice[i][v]=1;     //放入第i件物品
            }else{
                choice[i][v]=0;     //不放第i件物品
            }
        }
    }
    if(dp[m]!=m){
        printf("No Solution");  //无解
    }else{
        //记录最优路径
        int k=n,v=m,num=0;
        while(k>=0){
            if(choice[k][v]==1){
                flag[k]=1;
                v-=w[k];
                num++;
            }else{
                flag[k]=0;
            }
            k--;
        }
        //输出方案
        for(int i=n;i>=1;i--){
            if(flag[i]==1){
                printf("%d",w[i]);
                num--;
                if(num>0) printf(" ");
            }
        }
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《算法笔记》是由胡凡编写的一本关于算法学习的教材,它最初以C/C++为主要编程语言。这本教材主要面向想要学习算法的初学者,以及希望进一步提升算法能力的人群。 《算法笔记》的内容广泛而且深入,涵盖了很多算法的基础知识和主要思想,如递归、排序、查找、图论、动态规划等。通过学习这本教材,读者可以掌握这些算法的基本原理和实现方法,提高解决实际问题的能力。 该教材有几个特点:首先,它提供了很多例子和习题,帮助读者巩固所学的知识;其次,它介绍了很多常用的数据结构,如数组、链表、栈、队列等,读者可以通过学习这些数据结构更好地理解和应用算法;最后,它还介绍了一些高级主题,如高级数据结构、算法优化等,这些内容对于进一步提升算法水平非常有帮助。 《算法笔记》是一本入门级的教材,因此在阅读时需要一些基本的编程知识和逻辑思维能力。该教材的语言简洁明快,适合作为学习参考书,同时也可以作为算法竞赛的辅助教材。 总而言之,《算法笔记》是一本很好的算法学习教材,它以C/C++为编程语言,全面介绍了算法的基本知识和常用方法,适合想要学习算法的初学者。无论是学术研究还是实际应用,阅读《算法笔记》都能提升算法能力,并为进一步学习和应用算法打下坚实的基础。 ### 回答2: 《算法笔记 胡凡 c/c 快速入门pdf》是一本介绍算法和C/C++编程语言的入门书籍。该书的作者是胡凡,它主要规划了算法的学习路径以及基本的C/C++编程语言。这本书适合初学者快速入门,对于想要系统学习算法和C/C++编程的人来说是一本不错的选择。 这本书的内容非常系统和全面。它以算法和数据结构为基础,包括基本排序、查找、图论等算法的介绍和实践,让读者能够快速掌握这些算法的原理和实现方法。同时,它还介绍了C/C++语言的基础知识和编程技巧,帮助读者理解和运用这些知识。 书每章都有一些练习题,帮助读者巩固所学的知识。同时,每个章节末尾还提供了一些进阶的题目和参考答案,供读者深入学习和自我检测。这样的设计能够帮助读者更好地理解和掌握所学的内容。 总的来说,《算法笔记 胡凡 c/c 快速入门pdf》是一本很好的算法和C/C++入门书籍。它能够帮助读者快速了解算法和数据结构的基础知识,并学会使用C/C++语言进行编程。无论是对于想要入门算法和C/C++编程的初学者,还是已经有一定基础的读者,这本书都是一个很好的选择。 ### 回答3: 《算法笔记:胡凡C/C++快速入门PDF》是一本很棒的入门算法书籍。这本书主要介绍了常用的数据结构与算法,并通过C/C++语言来实现这些算法。 首先,这本书非常适合算法初学者。它从基础的数据结构开始讲解,如数组、链表、栈和队列,然后逐渐引入更复杂的数据结构,如二叉树、图和堆。此外,书还介绍了常用的排序和查找算法,如冒泡排序、快速排序、二分查找等。每个算法都配有具体的代码实现和详细的解释,帮助读者理解算法的原理和应用。 其次,这本书的学习资料丰富。书提供了很多例题和习题,读者可以通过实践来巩固所学的知识。此外,书还介绍了一些常见的算法优化技巧和设计思路,提供了一些高效解决问题的方法和思考方式。 最后,这本书的编写风格简明易懂。作者通过清晰的语言和简洁的代码,将复杂的算法问题简化为易于理解的部分。不论是对于算法初学者还是对于有一定编程基础的读者,这本书都是一本很好的学习资料。 总而言之,《算法笔记:胡凡C/C++快速入门PDF》是一本很好的入门算法书籍。它适合初学者学习和理解常用的数据结构与算法,通过具体的代码实现和详细的解释帮助读者掌握算法的原理和应用。无论是编程初学者还是有一定基础的读者,都可以从这本书获得丰富的知识和实践经验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值