ACM經典算法總結+代碼實現~

1.數的全排列(最基礎的dfs回溯)


/**********************************************
 *Author*        :coderdz
 *Created Time*  : 2019/1/7 23:31:48

*********************************************/

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <stack>
using namespace std;
#define IO ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define rep(i,n) for(int i=1;i<=n;i++)
#define m(a,b) memset(a,b,sizeof(a))
typedef pair<int, int> PII;
typedef long long LL;
const int MAXN=1e5+10;

inline void OPEN(string s){
    freopen((s + ".in").c_str(), "r", stdin);
    freopen((s + ".out").c_str(), "w", stdout);
}

int n,a[100],vis[100];

void dfs(int x){
	if (x>n){
		for(int i=1;i<n;i++)
			printf("%d ",a[i]);
		printf("%d\n",a[n]);
	}
	else{
		for(int i=1;i<=n;i++){
			if (!vis[i]){
				vis[i]=1;
				a[x]=i;
				dfs(x+1);
				vis[i]=0;
			}
		}
	}
}

int main(){
    scanf("%d",&n);
    m(vis,0);
    dfs(1);
    return 0;
}

python版

def dfs(x):
	if x>n:
		for i in range (1,n):
			print(a[i],end=' ')
		print(a[n])
	else:
		for i in range(1, n+1):
			if vis[i]==0:
				vis[i]=1
				a[x]=i
				dfs(x+1)
				vis[i]=0

n=int(input())
vis=[0]
a=[0]
for i in range(1,n+1):
	vis.append(0)
for i in range(1,n+1):
	a.append(0)
dfs(1)

2.漢諾塔(個人覺得最難理解的遞歸問題之一)

      求出對於不同的n(盤塊個數)的移動方法

#include<cstdio>

int cnt=0;

void move(int id,char a,char c){//打印移動方式:哪個盤子怎麼移動?
	printf("step %d :move %d from %c ---> %c\n",++cnt,id,a,c);
}

void solve_hanno(int n,char a,char b,char c){//遞歸過程
	if (n==1) move(n,a,c);
	else{
		solve_hanno(n-1,a,c,b);
		move(n,a,c);
		solve_hanno(n-1,b,a,c);
	}
}

int main(){
	int n;
	scanf("%d",&n);
	solve_hanno(n,'A','B','C');
	return 0;
}

python版

def move(n,a,c):
	global cnt #定義cnt全局變量,可進行讀寫
	cnt+=1
	print('step %d: move %d from %c ---> %c' % (cnt,n,a,c))
	
def solve_hanno(n,a,b,c):
	if n==1:
		move(n,a,c)
	else:
		solve_hanno(n-1,a,c,b)
		move(n,a,c)
		solve_hanno(n-1,b,a,c)

n=int(input())
cnt=0
solve_hanno(n,'A','B','C')

3.八皇后問題(經典dfs回溯)

/**********************************************
 *Author*        :coderdz
 *Created Time*  : 2019/1/17 21:51:00

*********************************************/

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <stack>
using namespace std;
#define IO ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define rep(i,n) for(int i=1;i<=n;i++)
#define m(a,b) memset(a,b,sizeof(a))
typedef pair<int, int> PII;
typedef long long LL;
const int MAXN=1e5+10;
int ans=0,a[15],b[15];

bool check(int row){
	for(int i=1;i<row;i++){
		if (a[i]==a[row] || abs(row-i)==abs(a[row]-a[i]))
			return false;
	}
	return true;
}

void dfs(int row,int n){//每個皇后放一行,只需要確定放哪一列
	if (row==n+1) ans++;//n行全部放完了,答案+1
	else{
		for(int i=1;i<=n;i++){//枚舉1~n列嘗試
			a[row]=i;//皇后放置在row行,i列
			if (check(row))
				dfs(row+1,n);
		}
	}
}

int main(){
	int n;
    scanf("%d",&n);
    dfs(1,n);
    printf("%d\n",ans);
    return 0;
}

4.迷宮問題(bfs遍歷)

    輸入一個字符迷宮矩陣,'.'代表可以通過,'#'代表不能通過,S爲起點,G爲終點,計算起點到終點的最短距離

/**********************************************
 *Author*        :coderdz
 *Created Time*  : 2019/1/7 23:31:48

*********************************************/

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <stack>
using namespace std;
#define IO ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define rep(i,n) for(int i=1;i<=n;i++)
#define m(a,b) memset(a,b,sizeof(a))
typedef pair<int, int> PII;
typedef long long LL;
const int MAXN=1e5+10;
int n,m,dis[105][105]={0};
int sx,sy,gx,gy;//起點和終點座標
int dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};//四個方向移動
char s[105][105];

void bfs(){
	queue<PII> q;
	q.push(PII(sx,sy));
	dis[sx][sy]=0;
	while(q.size()){//隊列不爲空
		PII p=q.front();
		q.pop();
		if (p.first==gx && p.second==gy) break;
		for(int i=0;i<4;i++){
			int x=p.first+dx[i];
			int y=p.second+dy[i];
			if (x<n&&x>=0&&y<m&&y>=0&&s[x][y]!='#'&&dis[x][y]==0){
				dis[x][y]=dis[p.first][p.second]+1;
				q.push(PII(x,y));
			}
		}	
	}
}

void init(){
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;i++)
		for(int j=0;j<m;j++)
			scanf(" %c",&s[i][j]);
	for(int i=0;i<n;i++)
		for(int j=0;j<m;j++){
			if (s[i][j]=='S'){
				sx=i;
				sy=j;
			}
			else if (s[i][j]=='G'){
				gx=i;
				gy=j;
			}
		}
}

int main(){
	init();
	bfs();
	printf("%d\n",dis[gx][gy]);
	return 0;
}

5.最短路之floyed算法

     O(n^3),多源最短路徑

/**********************************************
 *Author*        :coderdz
 *Created Time*  : 2019/1/7 23:31:48

*********************************************/

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <stack>
using namespace std;
#define IO ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define rep(i,n) for(int i=1;i<=n;i++)
#define m(a,b) memset(a,b,sizeof(a))
typedef pair<int, int> PII;
typedef long long LL;
const int MAXN=105;
int n,m,f[MAXN][MAXN];

int main(){
	scanf("%d%d",&n,&m);//無向圖,n個點,m條邊
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++){
			if (i==j) f[i][j]=0;
			else f[i][j]=1<<30;
		}
	int u,v,w;
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&u,&v,&w);
		f[u][v]=min(f[u][v],w);
	}
	for(int k=1;k<=n;k++)//枚舉中間點,必須放外層
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				if (f[i][j]>f[i][k]+f[k][j])
					f[i][j]=f[i][k]+f[k][j];
	printf("%d\n",f[1][n]);//節點1到節點n的距離
	return 0;
}

6.最短路之Dijkstra算法

     O(n^2),單源最短路徑,不能處理負邊權

/**********************************************
 *Author*        :coderdz
 *Created Time*  : 2019/1/7 23:31:48

*********************************************/

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <stack>
using namespace std;
#define IO ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define rep(i,n) for(int i=1;i<=n;i++)
#define m(a,b) memset(a,b,sizeof(a))
typedef pair<int, int> PII;
typedef long long LL;
const int MAXN=1e5;
int n,m,all;
int pre[MAXN],last[MAXN],other[MAXN],cost[MAXN],dis[MAXN],vis[MAXN];

void build(int u,int v,int w){
	pre[++all]=last[u];
	last[u]=all;
	other[all]=v;
	cost[all]=w;
}

void dijkstra(){
	for(int i=1;i<=n;i++){
		if (i==1) dis[i]=0;
		else dis[i]=1<<30;
	}
	int now=1;
	for(int i=1;i<=n;i++){
		vis[now]=1;//選入的點標記爲1
		int ed=last[now];
		while(ed!=-1){//遍歷當前點相連的所有邊然後進行鬆弛
			int dr=other[ed];
			if (!vis[dr])
				dis[dr]=min(dis[dr],dis[now]+cost[ed]);//鬆弛
			ed=pre[ed];
		}
		int pos,Min=1<<30;
		for(int i=1;i<=n;i++)//找到鬆弛後與當前點距離最短的點
			if (!vis[i])
				if (dis[i]<Min)
					Min=dis[i],pos=i;
		now=pos;
	}
}

int main(){
	scanf("%d%d",&n,&m);
	m(last,-1);
	m(vis,0);
	all=-1;
	for(int i=1;i<=m;i++){
		int a,b,w;
		scanf("%d%d%d",&a,&b,&w);
		build(a,b,w);
		build(b,a,w);
	}
	dijkstra();
	printf("%d\n",dis[n]);
	return 0;
}

7.最短路之SPFA算法

       隊列優化的Bellman-Ford算法,單源最短路,負權值但無環狀圖,O(KE)

/**********************************************
 *Author*        :coderdz
 *Created Time*  : 2019/1/18 16:39:22

*********************************************/

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <stack>
using namespace std;
#define IO ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define rep(i,n) for(int i=1;i<=n;i++)
#define m(a,b) memset(a,b,sizeof(a))
typedef pair<int, int> PII;
typedef long long LL;
const int MAXN=1e5+10;
int n,m,all;
int pre[MAXN],last[MAXN],other[MAXN],cost[MAXN],dis[MAXN];
bool vis[MAXN];

void build(int u,int v,int w){
	pre[++all]=last[u];
	last[u]=all;
	other[all]=v;
	cost[all]=w;
}

void bfs(int s){
	int now,ed,dr;
	queue<int> q;
	q.push(s);
	for(int i=1;i<=n;i++){
		if (i==s) dis[i]=0;
		else dis[i]=1<<30;
	}
	vis[s]=1;
	while(q.size()){
		now=q.front();
		q.pop();
		ed=last[now];
		while(ed!=-1){
			dr=other[ed];
			if (dis[now]+cost[ed]<dis[dr]){
				dis[dr]=dis[now]+cost[ed];
				if (!vis[dr]){
					vis[dr]=1;
					q.push(dr);
				}
			}
			ed=pre[ed];
		}
		vis[now]=0;
	}
}

int main(){
	all=-1;
	m(last,-1);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		int a,b,w;
		scanf("%d%d%d",&a,&b,&w);
		build(a,b,w);
		build(b,a,w);
	}
    m(vis,0);
    bfs(1);
    printf("%d\n",dis[n]);
    return 0;
}

8.最小生成樹(Kruskal算法)

     適用於稀疏圖

/**********************************************
 *Author*        :coderdz
 *Created Time*  : 2019/1/19 15:07:16

*********************************************/

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <stack>
using namespace std;
#define IO ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define rep(i,n) for(int i=1;i<=n;i++)
#define m(a,b) memset(a,b,sizeof(a))
typedef pair<int, int> PII;
typedef long long LL;
const int MAXN=1e5+10;
int fa[MAXN],n,m;

struct Node{
	int u,v,w;
}node[MAXN];

bool cmp(Node a,Node b){
	return a.w<b.w;
}

int find(int x){
	if (x==fa[x]) return x;
	return fa[x]=find(fa[x]);
}

void kruscal(){
	int sum=0;
	rep(i,m){
		int u=node[i].u,v=node[i].v;
		if (find(u)!=find(v)){//合併這兩個點到一棵樹上
			fa[find(v)]=find(u); 
			sum+=node[i].w;
		}//若兩個點在同一棵樹上,則捨棄掉這條邊,不加到sum中
	}
	printf("%d\n",sum);
}

void init(){
	while(~scanf("%d%d",&n,&m)){
		if (!n) break;
		rep(i,n) fa[i]=i;
		rep(i,m) scanf("%d%d%d",&node[i].u,&node[i].v,&node[i].w);
		sort(node+1,node+1+m,cmp);//對圖的邊進行從小到大排序,每次取最小的邊
		kruscal();
	}
}

int main(){
    //IO;
    init();
    return 0;
}

9.並查集

/**********************************************
 *Author*        :coderdz
 *Created Time*  : 2019/1/19 14:19:26

*********************************************/

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <stack>
using namespace std;
#define IO ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define rep(i,n) for(int i=1;i<=n;i++)
#define m(a,b) memset(a,b,sizeof(a))
typedef pair<int, int> PII;
typedef long long LL;
const int MAXN=1e5+10;

int fa[MAXN],n,m;

 
int find(int x){//查找根節點
	if (fa[x]==x) return x;
	else return fa[x]=find(fa[x]);
}

void join(int x,int y){//合併(y合併到x上)
	int fx=find(x),fy=find(y);
	if (fx!=fy) fa[fy]=fx;
}

void init(){//初始化
	scanf("%d%d",&n,&m);
	rep(i,n) fa[i]=i;
	rep(i,m){
		int a,b;
		scanf("%d%d",&a,&b);
		join(a,b);
	}
}

int main(){
	//IO;
	init();
	for(int i=1;i<=n;i++)
		printf("%d ",find(i));
	printf("\n");
    return 0;
}

10.樹狀數組(BIT)

     能夠完成下述操作的數據結構j(優點是速度快):    

        給定初始值全爲0的數列a1,a2,a3,·····,an

        1)給定i,計算a1+a2+···+ai

        2)給定ai和x,執行ai+=x

/**********************************************
 *Author*        :coderdz
 *Created Time*  : 2019/1/19 21:40:52
樹狀數組
*********************************************/

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <stack>
using namespace std;
#define IO ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define rep(i,n) for(int i=1;i<=n;i++)
#define m(a,b) memset(a,b,sizeof(a))
typedef pair<int, int> PII;
typedef long long LL;
const int MAXN=5e4+10;
int bit[MAXN],n,a[MAXN];

int lowbit(int x){//求某個數二進制表示中最低的一位1
	return x&(-x);
}

void add(int i,int x){
	while(i<=n){
		bit[i]+=x;
		i+=lowbit(i);
	}
}

int sum(int i){//求1~i的前綴和
	int ans=0;
	while(i>0){
		ans+=bit[i];
		i-=lowbit(i);
	}
	return ans;
}

int main(){
	m(bit,0);
	n=20;
	rep(i,n) a[i]=i;
	rep(i,n) add(i,a[i]);
	rep(i,n) printf("%3d ",a[i]);//原數組
	printf("\n");
	rep(i,n) printf("%3d ",bit[i]);//前綴數組
	printf("\n");
	rep(i,n) printf("%3d ",sum(i));//前綴和
	printf("\n");
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章