算法——完善中

技巧

错误原因
Uva1592: 没用对全局变量与部分变量进行清零操作

1.比较大的数组要开在main函数后面否则程序可能无法正常运行

 

2.使用重定向的文件方式测试数据更加方便

	freopen("data.in","r",stdin);
	freopen("data.out","w",stdout);

 

3.数组复制

#include<string.h>
memcpy(b,a,sizeof(a)) #将a复制到b中
memset(b,0,sizeof(b)) #reset b as 0
# the two Fun are in the same headfile

 

4.ctype.h

含有 isalpha() isdigit() toupper() tolower()
 

5.提升cin读取速度

取消cin与stdin的同步性

ios::sync_with_stdio(false);

 

6.在使用全局变量的时候千万记住要清空一下啊啊啊啊啊

 

7.使用vector 等迭代器的时候记得删除操作慎选iteration,用下标较好

 

8.解决除法过程中的向上取整

(n - 1)/ M + 1
 

9.优先队列的用法 priority_queue<>

1.对于内置类型
①默认优先级:

通过<操作符可知在整数中元素大的优先级高。

②传入比较结构体,自定义优先级
注意这里有些不同因为是比较a b 正常情况下通过<运算符比较 那么返回定义了>运算符返回 true就是反向了

#include <queue>
using namespace std;
 
struct cmp{
    bool operator ()(int a,int b){    //通过传入不同类型来定义不同类型优先级
        return a>b;    //最小值优先
    }
};
struct cmp{
    bool operator ()(int a,int b){
        return a<b;    //最大值优先
    }
};

priority_queue<int, vector<int>, cmp > q

或者简单方法代替

priority_queue<int, vector<int>,greater<int> >qq

2.对于自定义类型
重载了小于运算符即可

#include <queue>
using namespace std;
 
struct node {
    int priority;
    int value;
    friend bool operator < (const node &a, const node &b) {  
        return a.priority < b.priority;
    }

 

10.在列表操作中遇到字符串

可以通过一个map将字符串对应成相应的ID数字
 

11.stringstream的使用

头文件:sstream.h
sting s
对于大段的文章输入可以先使用getline(cin,s)  //遇到/n或者EOF终止
之后 stringstream  ss(s);
ss>>s; 类似cin 以空格为分割

12.泛型的算法

  1. accmulate()
    可以用于重载了加法的容器中
string str = accmulate(v.cbegin(),v.cend(),string(""));

2.equal()
比较v1中的元素是否与v2中的元素相同 v2至少要大于等于v13.

equal(v1.begin(),v1.end(),v2.begin());

3.copy()
进行元素的拷贝

auto ret = copy(v1.begin(),v1.end(),back_insert(v));  //将v1拷贝到v中

back_insert 定义在中

4.删除相同元素的操作
先使用sort
之后使用unique 将相同的值都放到了最后并且返回这些相同值的指针
之后调用erase即可擦除一个范围的值

读取时不省略空格

使用 getline(cin, str3) 即可不忽略空格读取前后都不忽略
还可以调用getline(cin, str3).eof()判断是否结尾
cin.eof()也可以判定是否结尾

注意浮点数相除时不要搞成了整数,加上小数点k

浮点数不能做相等比较,可以通分一下

枚举要看以下有没有相关性

算法

1.KMP字符串查找

在一个文本串 S 内查找一个模式串 P 的出现位置 (避免暴力搜索)
主要步骤
1.求出模式串的next数组
2.通过模式串数组在文本串中查找符合条件的模式串位置

查找算法实现

int KmpSearch(char* s, char* p)  
{  
    int i = 0;  
    int j = 0;  
    int sLen = strlen(s);  
    int pLen = strlen(p);  
    while (i < sLen && j < pLen)  
    {  
        //①如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++      
        if (j == -1 || s[i] == p[j])  
        {  
            i++;  
            j++;  
        }  
        else  
        {  
            //②如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j]      
            //next[j]即为j所对应的next值        
            j = next[j];  
        }  
    }  
    if (j == pLen)  
        return i - j;  
    else  
        return -1;  
}    

next数组算法实现

//优化过后的next 数组求法  
void GetNextval(char* p, int next[])  
{  
    int pLen = strlen(p);  
    next[0] = -1;  
    int k = -1;  
    int j = 0;  
    while (j < pLen - 1)  
    {  
        //p[k]表示前缀,p[j]表示后缀    
        if (k == -1 || p[j] == p[k])  
        {  
            ++j;  
            ++k;  
            //较之前next数组求法,改动在下面4行  
            if (p[j] != p[k])  
                next[j] = k;   //之前只有这一行  
            else  
                //因为不能出现p[j] = p[ next[j ]],所以当出现时需要继续递归,k = next[k] = next[next[k]]  
                next[j] = next[k];  
        }  
        else  
        {  
            k = next[k];  
        }  
    }  
} 

忘了具体分析点这里

后期学习写的完整代码

#include<cstdio>
#include<iostream>
#include<vector>
#include<string>
using namespace std;
vector<int> next_t;

void Getnext(string p)
{
	int pLen = p.size();
	next_t.push_back(-1);
	int k = -1;
	int j = 0;
	while (j < pLen - 1)
	{
		//p[k]表示前缀,p[j]表示后缀  
		if (k == -1 || p[j] == p[k])
		{
			++k;
			++j;
			next_t.push_back(k);
		}
		else
		{
			k = next_t[k];  //向前查找
		}
	}
}
int KmpSearch(string s, string p)
{
	int i = 0;
	int j = 0;
	int sLen = s.size();
	int pLen = p.size();
	while (i < sLen && j < pLen)
	{
		//①如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++      
		if (j == -1 || s[i] == p[j])
		{
			i++;
			j++;
		}
		else
		{
			//②如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next_t[j]      
			//next_t[j]即为j所对应的next_t值        
			j = next_t[j];
		}
	}
	if (j == pLen)
		return i - j;
	else
		return -1;
}
int main()
{
	string a, b;
	cin >> a >> b;
	next_t.clear();
	Getnext(b);
	if (KmpSearch(a,b))
	{
		cout << KmpSearch(a, b)<<endl;
	}
	return 0;
}

2.并查集与简单的同构查找

主要学习了一下并查集的概念 并查集主要就是两段代码一段查找的一段判断有没有链接在一块,没有的话连在一起

int pre[1000 ];
int find(int x)                                       //查找根节点
{ 
    int r=x;
    while ( pre[r] != r )                           //返回根节点 r
          r=pre[r];
 
    int i=x , j ;
    while( i != r )                                   //路径压缩
    {
         j = pre[ i ]; 				// 在改变上级之前用临时变量  j 记录下他的值 
         pre[ i ]= r ; 				//把上级改为根节点
         i=j;
    }
    return r ;
}
void join(int x,int y)                           //判断x y是否连通,
                                               //如果已经连通,就不用管了 如果不连通,就把它们所在的连通分支合并起,
{
    int fx=find(x),fy=find(y);
    if(fx!=fy)
        pre[fx ]=fy;
}
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
int pre_s[10100];
struct number
{
	int a;
	int b;
};
number s1_s[10100];//用于存储第一个图的一些环与链的情况  根节点
number s2_s[10100];//第二个

int find(int x)  //寻找根节点的函数 返回根节点
{
	int r = x;
	while (r != pre_s[r])
	{
		r = pre_s[r];
	}
	return r;
}
bool cmp(const number& a, const number& b)
{
	if (a.a == b.a)
	{
		return a.b > b.b;
	}
	else
	{
		return a.a > b.b;
	}
}
void init(int n)//初始化一下pre_s数组
{
	for (int i = 0; i < n; i++)
	{
		pre_s[i] = i;
	}
}
int main()
{
	int t, cas = 1;;
	scanf("%d", &t);
	while (t--)
	{
		for (int i = 1; i < 10010; i++)//第一次初始化
		{
			s1_s[i].a = 1; s1_s[i].b = 0;
			s2_s[i].a = 1; s2_s[i].b = 0;//最开始每个都是独立的,默认为链  
		}
		bool flag = false;
		int n1, m1, n2, m2;

		scanf("%d%d", &n1, &m1);
		init(n1);//初始化
		for (int i = 0; i < m1; i++)
		{
			int a, b;
			scanf("%d%d", &a, &b);
			int dx = find(a);
			int dy = find(b);
			if (dx != dy)  //没有存在过就是链存在过就成环了
			{
				pre_s[dx] = dy;
				s1_s[dy].a += s1_s[dx].a;
				s1_s[dx].a = 0;//把拉手的孩子数量加起来,下同  
			}
			else s1_s[dy].b = 1;//成环  
		}
		//again
		scanf("%d%d", &n2, &m2);
		init(n2);
		for (int i = 0; i < m2; i++)
		{
			int a, b;
			scanf("%d%d", &a, &b);
			int dx = find(a);
			int dy = find(b);
			if (dx != dy)
			{
				pre_s[dx] = dy;
				s2_s[dy].a += s2_s[dx].a;
				s2_s[dx].a = 0;
			}
			else s2_s[dy].b = 1;
		}
		if (n1 == n2) {

			sort(s1_s + 1, s1_s + n1 + 1, cmp);
			sort(s2_s + 1, s2_s + n2 + 1, cmp);//排序,若孩子的数量相同则对是否是环进行排序,这里要注意  

			for (int i = 0; i < n1; i++)
				if (s1_s[i].a != s2_s[i].a || s1_s[i].b != s2_s[i].b) {//判断数量,状态  
					flag = true;
					break;
				}
		}
		if (n1 != n2)    flag = true;

		if (flag) printf("Case #%d: NO\n", cas++);
		else printf("Case #%d: YES\n", cas++);
	}
	return 0;
}

3.迪杰斯特拉算法

// 邻接矩阵
typedef struct _graph
{
    char vexs[MAX];       // 顶点集合
    int vexnum;           // 顶点数
    int edgnum;           // 边数
    int matrix[MAX][MAX]; // 邻接矩阵
}Graph, *PGraph;

// 边的结构体
typedef struct _EdgeData
{
    char start; // 边的起点
    char end;   // 边的终点
    int weight; // 边的权重
}EData;
/*
 * Dijkstra最短路径。
 * 即,统计图(G)中"顶点vs"到其它各个顶点的最短路径。
 *
 * 参数说明:
 *        G -- 图
 *       vs -- 起始顶点(start vertex)。即计算"顶点vs"到其它顶点的最短路径。
 *     prev -- 前驱顶点数组。即,prev[i]的值是"顶点vs"到"顶点i"的最短路径所经历的全部顶点中,位于"顶点i"之前的那个顶点。
 *     dist -- 长度数组。即,dist[i]是"顶点vs"到"顶点i"的最短路径的长度。
 */
void dijkstra(Graph G, int vs, int prev[], int dist[])
{
    int i,j,k;
    int min;
    int tmp;
    int flag[MAX];      // flag[i]=1表示"顶点vs"到"顶点i"的最短路径已成功获取。

    // 初始化
    for (i = 0; i < G.vexnum; i++)
    {
        flag[i] = 0;              // 顶点i的最短路径还没获取到。
        prev[i] = 0;              // 顶点i的前驱顶点为0。
        dist[i] = G.matrix[vs][i];// 顶点i的最短路径为"顶点vs"到"顶点i"的权。
    }

    // 对"顶点vs"自身进行初始化
    flag[vs] = 1;
    dist[vs] = 0;

    // 遍历G.vexnum-1次;每次找出一个顶点的最短路径。
    for (i = 1; i < G.vexnum; i++)
    {
        // 寻找当前最小的路径;
        // 即,在未获取最短路径的顶点中,找到离vs最近的顶点(k)。
        min = INF;
        for (j = 0; j < G.vexnum; j++)
        {
            if (flag[j]==0 && dist[j]<min)
            {
                min = dist[j];
                k = j;
            }
        }
        // 标记"顶点k"为已经获取到最短路径
        flag[k] = 1;

        // 修正当前最短路径和前驱顶点
        // 即,当已经"顶点k的最短路径"之后,更新"未获取最短路径的顶点的最短路径和前驱顶点"。
        for (j = 0; j < G.vexnum; j++)
        {
            tmp = (G.matrix[k][j]==INF ? INF : (min + G.matrix[k][j])); // 防止溢出
            if (flag[j] == 0 && (tmp  < dist[j]) )
            {
                dist[j] = tmp;
                prev[j] = k;
            }
        }
    }

    // 打印dijkstra最短路径的结果
    printf("dijkstra(%c): \n", G.vexs[vs]);
    for (i = 0; i < G.vexnum; i++)
        printf("  shortest(%c, %c)=%d\n", G.vexs[vs], G.vexs[i], dist[i]);
}

4.数论

1.最大公因数


//两个数的最大公约数-—辗转相除法
int gcd(int a, int b){
    //总是将较小的数放在b中
    if(a < b){
        swap(a, b);
    }
    if(b == 0){
        return a;
    }
    else{
        return gcd(b, a%b);
    }
}

2.最小公倍数等于两数相乘除以最大公因数

观察区间是否满足的波动性问题

看一个区间 [a,b] [c,d] 等是否满足 在 k的波动下找到一组数使得其满足区间

#include<iostream>
#include <vector>
#include<algorithm>
using namespace std;
typedef long long ll;

int main() {
	int t;
	scanf("%d", &t);
	while (t--) {
		int a;
		ll b;
		scanf("%d %lld", &a, &b);
		bool flag = true;
		vector<ll> vmax, vmin;
		for (int i = 0; i != a; i++) {
			ll c, d;
			scanf("%lld %lld", &c, &d);
			if (i == 0)vmax.push_back(d), vmin.push_back(c);
			else {
				vmin.push_back(max(c, vmin.back() - b));  //当前在这一步所能达到的最小值
				vmax.push_back(min(d, vmax.back() + b));  //当前在这一步所能达到的最大值
			}
			if (vmin.back() > vmax.back())flag = false;
		}
		if (!flag)printf("NO\n");
		else {
			vector<ll> ans;
			ll now = vmin.back();
			ans.push_back(now);
			for (int i = 0; i != a - 1; i++) {
				vmin.pop_back();
               //if (vmin.back() > now + b)flag = false;
				now = max(vmin.back(), now - b);
				ans.push_back(now);
			}
			//if (!flag) {
			//	printf("NO\n");
			//	continue;
			//}
			printf("YES\n");
			for (ll i = ans.size() - 1; i != -1; i--) {
				printf("%d", ans[i]);
				if (i)putchar(' ');
			}
			putchar('\n');
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值