一本通 搜索与回溯专栏

全排列问题(form.cpp)

【问题描述】

输出自然数1 到n 所有不重复的排列,即n 的全排列,要求所产生的任一数字序列中不允许出现重复的

数字。

【输入形式】

n(1≤n≤9)

【输出形式】

由1~n 组成的所有不重复的数字序列,每行一个序列。

【样例输入】

3
【样例输出】

1 2 3

1 3 2

2 1 3

2 3 1

3 1 2

3 2 1

#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
# include<iostream>
# include<algorithm>
# include<cmath>
# include<cstdio>
# include<set>
# include<stack>
# include<queue> 
# include<map>
# include<string>
# include<cstring> 
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int > PII; 
const int mod=1e9+7;
const int MAX=2e6+10;
const int Time=86400;
const int X=131;
const int inf=0x3f3f3f3f;
const double PI = 1e-4;
double pai = 3.14159265358979323846; 

int a[10],n;
int vis[10];
void dfs(int u){
	if(u == n + 1){
		 for(int j = 0 ; j < n ; j ++ )
		  cout<<a[j]<<" ";
		cout<<"\n";
		return ;
	}
	for(int i = 1 ; i <= n ; i ++ ){
		if(!vis[i]){}
		  vis[i] = 1; 
		  a[u] = i;
		  dfs(u+1);
		  vis[i] = 0;	
		}
		 
	}
}
int main(){  
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> n;
    dfs(1);
	return 0;
}

组合的输出

【问题描述】

排列与组合是常用的数学方法,其中组合就是从n个元素中抽出r个元素(不分顺序且r≤n),我们可以简单地将n个元素理解为自然数1,2,…,n,从中任取r个数。

现要求你用递归的方法输出所有组合。

例如n=5,r=3,所有组合为:

1 2 3 1 2 4 1 2 5 1 3 4 1 3 5 1 4 5 2 3 4 2 3 5 2 4 5 3 4 5

【输入形式】

一行两个自然数n、r(1<n<21,1<=r<=n)。

【输出形式】

所有的组合,每一个组合占一行且其中的元素按由小到大的顺序排列,所有的组合也按字典顺序。

【样例输入】

5 3
【样例输出】

1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5



#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
# include<iostream>
# include<algorithm>
# include<cmath>
# include<cstdio>
# include<set>
# include<stack>
# include<queue> 
# include<map>
# include<string>
# include<cstring> 
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int > PII; 
const int mod=1e9+7;
const int MAX=2e6+10;
const int Time=86400;
const int X=131;
const int inf=0x3f3f3f3f;
const double PI = 1e-4;
double pai = 3.14159265358979323846; 

int a[10],n,m;
int vis[10];
void dfs(int u,int s){
	if(s == m + 1){
		 for(int j = 1 ; j <= m ; j ++ )
		  cout<<a[j]<<" ";
		cout<<"\n";
		return ;
	}
	for(int i = u ; i <= n ; i ++ ){
		  if(i>a[s-1]){
	
		  	a[u] = i;
		    dfs(u+1,s+1);
	
	 }
	
		  
		
		}
		 
	
}
int main(){  
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> m;
    dfs(1,1);
	return 0;
}

N 皇后问题(queen)

【问题描述】

在N*N 的棋盘上放置N 个皇后(n<=10)而彼此不受攻击(即在棋盘的任一行,任一列和任一对角线上

不能放置2 个皇后),编程求解所有的摆放方法。

在这里插入图片描述

【输入形式】

输入:n

【输出形式】

每行输出一种方案,每种方案顺序输出皇后所在的列号,各个数之间有空格隔开。若无方案,则输出

no solute!

【样例输入】

4
【样例输出】

2 4 1 3

3 1 4 2


#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
# include<iostream>
# include<algorithm>
# include<cmath>
# include<cstdio>
# include<set>
# include<stack>
# include<queue> 
# include<map>
# include<string>
# include<cstring> 
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int > PII; 
const int mod=1e9+7;
const int MAX=2e6+10;
const int Time=86400;
const int X=131;
const int inf=0x3f3f3f3f;
const double PI = 1e-4;
double pai = 3.14159265358979323846; 

int col[15],arg[15],unarg[15],vis[15][15];
int a[15],n,flag;
void dfs(int i){
    if(i == n+1){
    	flag = 1;
    	 for(int i = 1 ; i <= n ; i ++){
    	 	 cout<<a[i]<<" ";
		 }
		 cout<<"\n";
		 return ;
	}	 
	for(int j = 1 ; j <= n ;j ++ ){
		 if(!col[j] && !arg[n + i - j] && !unarg[i+j] ){
		 	  col[j] = arg[n + i - j] = unarg[i+j] = 1;
		 	  a[i] = j;
		 	  dfs(i+1);
		 	 col[j] = arg[n + i - j] = unarg[i+j] = 0;
		 }
	}
}
int main(){  
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> n;
    dfs(1);
    if(flag == 0) cout<<"no solute!";
	return 0;
}

有重复元素的排列问题(perm)

【问题描述】

设R={ r1, r2 , …, rn}是要进行排列的n个元素。其中元素r1, r2 , …, rn可能相同。试设计一个算法,

列出R的所有不同排列。

给定n 以及待排列的n 个元素。计算出这n 个元素的所有不同排列。

【输入形式】

输入数据:

文件的第1 行是元素个数n,1≤n≤500。接下来的1 行是待排列的n个元素。

【输出形式】

计算出的n个元素的所有不同排列输出。文件最后1行中的数是排列总数。

【样例输入】

4

aacc

【样例输出】

aacc

acac

acca

caac

caca

ccaa

6


#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
# include<iostream>
# include<algorithm>
# include<cmath>
# include<cstdio>
# include<set>
# include<stack>
# include<queue> 
# include<map>
# include<string>
# include<cstring> 
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int > PII; 
const int mod=1e9+7;
const int MAX=2e6+10;
const int Time=86400;
const int X=131;
const int inf=0x3f3f3f3f;
const double PI = 1e-4;
double pai = 3.14159265358979323846; 

int n,sum;
int vis[10];
char s[505];


int main(){  
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> s;
    sort(s,s+n);
	do{
		 cout<<s<<"\n";
		sum++;
	}while(next_permutation(s,s+n));
    cout<<sum;
	return 0;
}

子集和问题(subsum)

【问题描述】

子集和问题的一个实例为〈S,t〉。其中,S={ x1, x2,…, xn}是一个正整数的集合,c是一个正整

数。子集和问题判定是否存在S的一个子集S1,使得子集S1和等于c。

对于给定的正整数的集合S={ x1, x2,…, xn}和正整数c,编程计算S 的一个子集S1,使得子集S1和等于c。

【输入形式】

输入共两行,第一行有2个正整数n和c,n表示S的个数,c是子集和的目标值。接下来一行中,有n个正整数,表示集合S中的元素。

【输出形式】

输出子集和问题的解;当问题和无解时,输出"No Solution!"。

【样例输入】

5 10
2 2 6 5 4
【样例输出】

2 2 6
【样例说明】

1、n<10000、c<10000000

2、如果有解,只需要输出“最靠前”的一个解


#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
# include<iostream>
# include<algorithm>
# include<cmath>
# include<cstdio>
# include<set>
# include<stack>
# include<queue> 
# include<map>
# include<string>
# include<cstring> 
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int > PII; 
const int mod=1e9+7;
const int MAX=2e6+10;
const int Time=86400;
const int X=131;
const int inf=0x3f3f3f3f;
const double PI = 1e-4;
double pai = 3.14159265358979323846; 

int n , m, a[MAX],ans,flag,sum;
bool vis[MAX];
void print(int i) {
	for (int j = 0; j <= i; j++) {
		if (vis[j] == true) {
			if (j != i) cout<<a[j]<<" ";
			else cout<<a[j];
		}
	}
}
void dfs(int u){

	if (u >= n || flag) 	return;	
	vis[u] = true;
	ans += a[u];
	
	if (ans == m) {
		print(u);
		flag = 1;
	  
	}
	else if (ans < m) {
		dfs(u + 1);
	}
	
	vis[u] = false;
	ans -= a[u];
	dfs(u + 1);
	return;
}
int main(){  
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> m;
    for(int i = 0 ; i < n ; i ++ ) cin >> a[i],sum+=a[i];
   if(sum < m){
    	 cout<<"No Solution!";
    	 return 0;
	}
	if(sum == m){
		 for(int i = 0 ;i < n ; i++ )
		  cout<<a[i]<<" ";
		  
		  return 0;
	} 
    dfs(0);
    if(flag == 0 )cout<<"No Solution!";
	return 0;
}

工作分配问题(job)

【问题描述】

设有n件工作分配给n个人。将工作i分配给第j个人所需的费用为cij。试设计一个算法,为每一个人都分配一件不同的工作,并使总费用达到最小。

设计一个算法,对于给定的工作费用,计算最佳工作分配方案,使总费用达到最小。

【输入形式】

输入共两行,第一行有一个正整数n(1<=n<=20)。接下来的n行,每行n个数,第i行表示第i个人各项工作费用。

【输出形式】

输出最小总费用

【样例输入】

3
4 2 5
2 3 6
3 4 5
【样例输出】

9


#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
# include<iostream>
# include<algorithm>
# include<cmath>
# include<cstdio>
# include<set>
# include<stack>
# include<queue> 
# include<map>
# include<string>
# include<cstring> 
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int > PII; 
const int mod=1e9+7;
const int MAX=2e6+10;
const int Time=86400;
const int X=131;
const int inf=0x3f3f3f3f;
const double PI = 1e-4;
double pai = 3.14159265358979323846; 
int n, a[25][25];
bool vis[25];
int ans;

void dfs(int u,int sum){
	if(u == n){
		 ans = min(ans,sum);
		 return ;
	}
	if(sum > ans) return ;
	for(int i = 0 ; i < n ; i++ ){
		 if(!vis[i]){
		 	 vis[i] = true;
		 	 dfs(u+1,sum+a[u][i]);
		 	 vis[i] = false ;
		 }
	}
}
int main(){  
   std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> n;
    for(int i = 0 ; i < n ; i ++ )
     for(int j = 0 ; j < n ; j ++ )
      cin >> a[i][j] , ans+=a[i][j];
    dfs(0,0);
    cout<<ans;
	return 0;
}

装载问题(load)

【问题描述】

有一批共n个集装箱要装上艘载重量为c的轮船,其中集装箱i的重量为wi。找出一种最优装载方案,将轮船尽可能转满,即在装载体积不受限制的情况下,将尽可能重的集装箱装上轮船。

【输入形式】

输入共2行,第一行有2个正整数n和c。n是集装箱数,c是轮船的载重量。接下来的1行中有n个正整数,表示集装箱的重量。

【输出形式】

输出最大装载重量

【样例输入】

5 10
7 2 6 5 4
【样例输出】

10


#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
# include<iostream>
# include<algorithm>
# include<cmath>
# include<cstdio>
# include<set>
# include<stack>
# include<queue> 
# include<map>
# include<string>
# include<cstring> 
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int > PII; 
const int mod=1e9+7;
const int MAX=2e6+10;
const int Time=86400;
const int X=131;
const int inf=0x3f3f3f3f;
const double PI = 1e-4;
double pai = 3.14159265358979323846; 

int dp[MAX],n,m;

int main(){  
   std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> m;
    for(int i = 0 ; i < n ; i ++ ) {
    	 int v;
    	 cin >> v;
    	 for(int j = m ; j >= v ; j -- )
    	  dp[j] = max(dp[j],dp[j-v] + v);
	}
	cout<<dp[m];
	return 0;
}

字符序列(characts)

【问题描述】

从三个元素的集合[A,B,C]中选取元素生成一个N个字符组成的序列,使得没有两个相邻字的子序列相同。例:N = 5时ABCBA是合格的,而序列ABCBC与ABABC是不合格的,因为其中子序列BC,AB是相同的。

【输入形式】

输入仅有一个整数n(1<=n<=15)。

【输出形式】

输出满足条件的N个字符的序列总数。

【样例输入】

4
【样例输出】

18

#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
# include<iostream>
# include<algorithm>
# include<cmath>
# include<cstdio>
# include<set>
# include<stack>
# include<queue> 
# include<map>
# include<string>
# include<cstring> 
`using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int > PII; 
const int mod=1e9+7;
const int MAX=2e6+10;
const int Time=86400;
const int X=131;
const int inf=0x3f3f3f3f;
const double PI = 1e-4;
double pai = 3.14159265358979323846; 
int n, ans, a[MAX];
void dfs(int u)
{
    if(u > n ){
    	 ans++;
    	 return ;
	}
    for(int i = 1; i <= 3; i ++)
    {   
        if(i == a[u - 2] && a[u - 1] == a[u - 3]) continue;
        a[u] = i;
        dfs(u+1);
    }
}
 
int main()
{
   
    cin>>n;
    dfs(1);
    cout<<ans;
    return 0;
}

试卷批分(grade)

【问题描述】

某学校进行了一次英语考试,共有10道是非题,每题为10分,解答用1表示“是”,用0表示“非”的方式。但老师批完卷后,发现漏批了一张试卷,而且标准答案也丢失了,手头只剩下了3张标有分数的试卷。

在这里插入图片描述

请编一程序依据这三张试卷,算出漏批的那张试卷的分数。

【输入形式】

【输出形式】

【样例输入】

0 0 1 0 1 0 0 1 0 0

【样例输出】

70

#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
# include<iostream>
# include<algorithm>
# include<cmath>
# include<cstdio>
# include<set>
# include<stack>
# include<queue> 
# include<map>
# include<string>
# include<cstring> 
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int > PII; 
const int mod=1e9+7;
const int MAX=2e6+10;
const int Time=86400;
const int X=131;
const int inf=0x3f3f3f3f;
const double PI = 1e-4;
double pai = 3.14159265358979323846; 

int n;
int vis[10];
int s[5];
int a[5][11]={
              {0,0,0,0,0,0,0,0,0,0,0}, 
              {0,0,0,1,0,1,0,0,1,0,0},
              {0,0,1,1,1,0,1,0,1,1,1},
              {0,0,1,1,1,0,0,0,1,0,1},
              {0,0,0,1,1,1,0,0,1,1,1}
             };
void dfs(int x){
   for(int i=0;i<=1;i++)
    {
        for(int j=1;j<=4;j++)
            if(a[j][x]==i)
                s[j]+=10;
        if(x==10) 
        {
            if(s[1]==70 && s[2]==50 && s[3]==30)
            {
                cout<<s[4]<<endl;
                return;
            }
        }
        else dfs(x+1);
        for(int j=1;j<=4;j++)
            if(a[j][x]==i)
                s[j] -= 10;
    }
}
int main(){  
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    for(int i = 0 ; i < 10 ; i++ ) cin >> n;
    dfs(0);
	return 0;
}

迷宫问题(migong)

【问题描述】

设有一个 N*N(2<=N<10)方格的迷宫,入口和出口分别在左上角和右上角。迷宫格子中

分别放0 和1,0 表示可通,1 表示不能,入口和出口处肯定是0。迷宫走的规则如下所示:

即从某点开始,有八个方向可走,前进方格中数字为0 时表示可通过,为1 时表示不可通过,

要另找路径。找出所有从入口(左上角)到出口(右上角)的路径(不能重复),输出路径总

数,如果无法到达,则输出0。

【输入形式】

第一行为方阵N

接下来的N行为方阵值。
【输出形式】

路径总数.

【样例输入】

3

0 0 0

0 1 1

1 0 0

【样例输出】

2

#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
# include<iostream>
# include<algorithm>
# include<cmath>
# include<cstdio>
# include<set>
# include<stack>
# include<queue> 
# include<map>
# include<string>
# include<cstring> 
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int > PII; 
const int mod=1e9+7;
const int MAX=2e6+10;
const int Time=86400;
const int X=131;
const int inf=0x3f3f3f3f;
const double PI = 1e-4;
double pai = 3.14159265358979323846; 

int n,m,ans;
int a[25][25];
bool vis[25][25];
int dx[8]={-1,0,1,0,1,1,-1,-1};
int dy[8]={0,1,0,-1,1,-1,1,-1};


void dfs(int x, int y){
	if(x == 1 && y == n){
		 ans++;
		 return ;
	}
	for(int i = 0 ; i < 8 ; i++ ){
		 int xx = x + dx[i];
		 int yy = y + dy[i];
		 if(xx >= 1 && xx <= n && yy >= 1&& yy <= n && !vis[xx][yy] && !a[xx][yy])
		  {
		  	vis[xx][yy] = true;
		  	dfs(xx,yy);
		  	vis[xx][yy] = false;
		  }
	}
}

int main(){  
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> n ;
    for(int i = 1 ; i <= n ;i ++ )
     for(int j = 1 ; j <= n ; j ++ )
      cin >> a[i][j];
    vis[1][1] = true;
    dfs(1,1);
    cout<<ans;
	return 0;
}

部落卫队

【问题描述】

原始部落byteland中的居民们为了争夺有限的资源,经常发生冲突。几乎每个居民都有他的仇敌。部落酋长为了组织一支保卫部落的队伍,希望从部落的居民中选出最多的居民入伍,并保证队伍中任何2个人都不是仇敌。

编程任务:

给定byteland部落中居民间的仇敌关系,编程计算组成部落卫队的最佳方案。

【输入形式】

第一行有2个正整数n和m,表示byteland部落中有n个居民,居民间有m个仇敌关系。居民编号1,2,3…,n。接下来的m行中,每行有2个正整数u和v,表示居民u与居民v是仇敌。

【输出形式】

第一行是部落卫队的总人数;第二行是卫队组成xi,1<=i<=n<=100,xi=0表示居民i不在卫队中,xi=1表示居民i在卫队中。如果有多种方案,输出字典序大的。

【样例输入】

7 10

1 2

1 4

2 4

2 3

2 5

2 6

3 5

3 6

4 5

5 6

【样例输出】

3

1 0 1 0 0 0 1

#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
# include<iostream>
# include<algorithm>
# include<cmath>
# include<cstdio>
# include<set>
# include<stack>
# include<queue> 
# include<map>
# include<string>
# include<cstring> 
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int > PII; 
const int mod=1e9+7;
const int MAX=2e6+10;
const int Time=86400;
const int X=131;
const int inf=0x3f3f3f3f;
const double PI = 1e-4;
double pai = 3.14159265358979323846; 

int a[MAX],n,m,x[MAX],ans,mp[105][105],sum;

void dfs(int u,int sum){
      if(u > n ){
      	  if(sum <= ans) return;
      	  ans = sum;
      	  for(int i = 1; i <= n ; i ++ )
      	   a[i] = x[i];
      	return ;
	  }
	  int flag = 1;
	  for(int j = 1 ; j < u ; j ++ ){
	  	 if(mp[j][u] && x[j]) {
	  	 	 flag = 0 ;
	  	 	 break;
		   }
	  }
	  
	  if(flag){
	  	  x[u] = 1;
	  	  dfs(u+1,sum+1);
	  	  x[u] = 0;
	  }
	  
	  dfs(u+1,sum);
}
int main(){  
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> m;
    for(int i = 1; i <= m ; i ++ ){
    	 int u ,v;
    	 cin >> u >> v;
    	 mp[u][v] = mp[v][u] = 1;
	}
	dfs(1,0);
	cout<<ans<<"\n";
	for(int i = 1 ; i <= n ; i ++ )
	 cout<<a[i]<<" ";
	return 0;
}

最佳调度问题

【问题描述】

假设有n个任务由k个可并行工作的机器完成。完成任务i需要的时间为ti.试设计一个算法找出完成这n个任务的最佳调度,使得完成全部任务的时间最早。

编程任务:

对任意给定的整数n和k ,以及完成任务i需要的时间为ti,i=1~n。编程计算完成这n个任务的最佳调度。

【输入形式】

第一行有2个正整数n和k;第2行的n个正整数是完成n个任务需要的时间。(1≤n≤20,1≤k≤6)

【输出形式】

输出完成全部任务的最早时间ti(1≤ti≤100)。

【样例输入】

7 3

2 14 4 16 6 5 3

【样例输出】

17

#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
# include<iostream>
# include<algorithm>
# include<cmath>
# include<cstdio>
# include<set>
# include<stack>
# include<queue> 
# include<map>
# include<string>
# include<cstring> 
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int > PII; 
const int mod=1e9+7;
const int MAX=2e6+10;
const int Time=86400;
const int X=131;
const int inf=0x3f3f3f3f;
const double PI = 1e-4;
double pai = 3.14159265358979323846; 

int n , k ,a[MAX] , ans,num[MAX],tot;

void dfs(int x){ 
     if(x > n){
     	  int res = num[1];
     	for(int i = 2; i <= k ; i++ )
     	   res = max(res,num[i]);
     	
     	 ans = min(ans,res);
     	 return ;
     
	 }
	 else{
	 	   for(int i = 1 ; i <= tot - 1 ; i ++ ){
	 	   	     if(num[i] + a[x] <= ans){
	 	   	     	     num[i] += a[x];
	 	   	     	     dfs(x+1);
	 	   	     	     num[i] -= a[x];
					 }
			}
			
		
	 	  if(tot <= k){
	 	   	     num[tot++] += a[x];
	 	   	     dfs(x+1);
	 	   	     num[--tot] -= a[x];
			}
	 	
	 }
}

int main(){  
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> k;
    for(int i = 1 ; i <= n ; i ++ ) cin >> a[i],ans+=a[i];
    sort(a + 1,a + 1 + n);
    
    num[1] += a[1];
    tot = 2;
    dfs(2);
    cout<<ans;
	return 0;
}

图的m着色问题

【问题描述】

给定无向连通图G和m种不同的颜色。用这些颜色为图G的各顶点着色,每个顶点着一种颜色。如果有一种着色法使G中每条边的2个顶点着不同颜色,则称这个图是m可着色的。图的m着色问题是对于给定图G和m种颜色,找出所有不同的着色法。

编程任务:

对于给定的无向连通图G和m种不同的颜色,编程计算图的所有不同的着色法。

【输入形式】

第1行有3个正整数n,k和m,表示给定的图G有n个顶点和k条边,m种颜色。顶点编号为1,2,…,n。接下来k行中,每行有2个正整数u,v,表示图G的一条边(u,v)。(n<=100)

【输出形式】

输出计算出的不同的着色方案数。

【样例输入】

5 8 4

1 2

1 3

1 4

2 3

2 4

2 5

3 4

4 5

【样例输出】

48

#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
# include<iostream>
# include<algorithm>
# include<cmath>
# include<cstdio>
# include<set>
# include<stack>
# include<queue> 
# include<map>
# include<string>
# include<cstring> 
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int > PII; 
const int mod=1e9+7;
const int MAX=2e6+10;
const int Time=86400;
const int X=131;
const int inf=0x3f3f3f3f;
const double PI = 1e-4;
double pai = 3.14159265358979323846; 

int n,m,k,ans;
int colour[105];
int mp[105][105];
bool check(int x){
	for(int i = 1 ; i <= n ; i ++ ){
		 if(mp[x][i] && mp[i][x]  && colour[x] == colour[i]) return false;
	}
	return true;
}
void dfs(int u){
    if(u > n){
    	 ans++;
    	 return ;
	}
    for(int i = 1 ; i <= m ; i ++ ){
    	  colour[u] = i;
    	  if(check(u)){
    	  	 dfs(u + 1);
		  }
    	  colour[u] = 0;
	}
}
int main(){  
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> k >> m;
    for(int i = 1 ; i <= k ; i ++ ){
    	 int u , v;
    	 cin >> u >> v;
    	 mp[u][v] = mp[v][u] = 1;
	}
	dfs(1);
	cout<<ans;
	return 0;
}

自然数的拆分问题

【问题描述】

任何一个大于1的自然数n,总可以拆分成若干个小于n的自然数之和。

【输入形式】

输入一个自然数n.

【输出形式】

输出不同的拆分方法,每一种拆分方法输出到一行。

【样例输入】

7
【样例输出】

1+1+1+1+1+1+1

1+1+1+1+1+2

1+1+1+1+3

1+1+1+2+2

1+1+1+4

1+1+2+3

1+1+5

1+2+2+2

1+2+4

1+3+3

1+6

2+2+3

2+5

3+4

#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
# include<iostream>
# include<algorithm>
# include<cmath>
# include<cstdio>
# include<set>
# include<stack>
# include<queue> 
# include<map>
# include<string>
# include<cstring> 
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int > PII; 
const int mod=1e9+7;
const int MAX=2e6+10;
const int Time=86400;
const int X=131;
const int inf=0x3f3f3f3f;
const double PI = 1e-4;
double pai = 3.14159265358979323846; 
int n, a[25];
bool vis[25];
int ans;

void dfs(int ans,int j,int now){
	 if(ans==n)  {
	 	            for(int i=1;i<=j-1;i++)
	 	             if(i==1) cout<<a[i];
	 	             else     cout<<"+"<<a[i];
	 	             cout<<"\n";
	 	             return ;
	             }
	 if(ans>n) return ;
	 for(int i=now;i<=n-1;i++){
	 	 a[j]=i;
	 	 dfs(ans+i,j+1,i);
	 	 a[j]=0;
	 }
}
int main(){  
   std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> n;
    dfs(0,1,1);
	return 0;
}

整数的划分(Noip2001)

【问题描述】

将整数nn分成kk份,且每份不能为空,任意两份不能相同(不考虑顺序)。

例如:n=7n=7,k=3k=3,下面三种分法被认为是相同的。

{1,1,5};{1,5,1};{5,1,1}{1,1,5};{1,5,1};{5,1,1};

问有多少种不同的分法。 输出一个整数,即不同的分法。

【输入形式】

两个整数nn,k(6<n≤200,2≤k≤6)k(6<n≤200,2≤k≤6),中间用单个空格隔开。
【输出形式】

一个整数,即不同的分法。

【样例输入】

7 3
【样例输出】

4
【样例说明】

四种分法为:{1,1,5};{1,2,4};{1,3,3};{2,2,3}{1,1,5};{1,2,4};{1,3,3};{2,2,3}。

#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
# include<iostream>
# include<algorithm>
# include<cmath>
# include<cstdio>
# include<set>
# include<stack>
# include<queue> 
# include<map>
# include<string>
# include<cstring> 
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int > PII; 
const int mod=1e9+7;
const int MAX=2e6+10;
const int Time=86400;
const int X=131;
const int inf=0x3f3f3f3f;
const double PI = 1e-4;
double pai = 3.14159265358979323846; 

int ans,n,m;
void dfs(int pos,int sum,int cnt){
	   if(cnt == m){
	   	   if(sum == n) ans++;
	   	   return ;
	   }
	   if(sum > n ) return ;
	  for(int i = pos ; i <= n ; i ++ ){
	  	 if(sum + (m - cnt) * i <= n )
		    dfs(i,sum + i , cnt + 1);
	  }
}
int main(){  
   std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> m;
    dfs(1,0,0);
    cout<<ans;
	return 0;
}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,以下是使用回溯法解决部落卫队问题的具体代码,可以参考。 ```python def backtracking(i, mask, n, m, adj, ans): """ i: 当前考虑的点 mask: 当前已经选中的点的状态 n: 点的总数 m: 边的总数 adj: 图的邻接表表示 ans: 当前最优解 """ if i == n: # 已经遍历完所有的点,统计当前方案的连块数量 cnt = 0 for j in range(n): if mask & (1 << j): cnt += 1 ans[0] = min(ans[0], cnt) return # 不选当前点 backtracking(i + 1, mask, n, m, adj, ans) # 选当前点 if (mask & (1 << i)) == 0: # 当前点还没有被选中,可以考虑选中 flag = True for j in range(len(adj[i])): if mask & (1 << adj[i][j]): # 如果当前点与其邻接点已经都被选中了,则不能再选中当前点 flag = False break if flag: # 如果可以选中当前点,则将其加入到当前状态中 backtracking(i + 1, mask | (1 << i), n, m, adj, ans) # 读入数据 n, m = map(int, input().split()) adj = [[] for i in range(n)] for i in range(m): u, v = map(int, input().split()) adj[u - 1].append(v - 1) adj[v - 1].append(u - 1) ans = [n + 1] backtracking(0, 0, n, m, adj, ans) # 输出结果 for i in range(n): if ans[0] == n: print(0, end=' ') elif ans[0] == 1: print(1, end=' ') elif (ans[0] == 2) and ((1 << i) & mask): print(1, end=' ') else: print(0, end=' ') print() ``` 其中,`backtracking` 函数用于进行回溯,`i` 表示当前考虑的点,`mask` 表示当前已经选中的点的状态,`n` 表示点的总数,`m` 表示边的总数,`adj` 表示图的邻接表表示,`ans` 表示当前最优解。 在 `backtracking` 函数中,首先考虑不选当前点的情况,然后再考虑选当前点的情况。如果当前点还没有被选中,可以考虑选中,需要判断当前点与其邻接点是否已经都被选中了,如果是,则不能再选中当前点。如果可以选中当前点,则将其加入到当前状态中,并继续考虑下一个点。 最终在 `ans` 中记录的是当前最优解,即连块数量最小的方案。最后根据 `ans` 中的结果,输出每个点是否被选中。如果最优解为 $n$,则说明所有点都是一个连块,输出 $0$;如果最优解为 $1$,则说明所有点都是单独的连块,输出 $1$;如果最优解为 $2$,则说明除了一个连块,其他点都是单独的连块,输出 $1$ 的点为连块的点,其他点输出 $0$。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值