ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

ACM必备模板——动态规划

2021-11-30 22:00:03  阅读:100  来源: 互联网

标签:const int 必备 cin ACM ++ using include 模板


动态规划

文章目录

背包问题

01背包 ——每件物品只能使用一次。

  • 状态方程 :f[i][j] = max(f[i-1][j],f[i-1][j-v[i]]+w[i]);
二维
#include<iostream>
#include<algorithm>


using namespace std;

const int N =10010;

int v[N],w[N];  // 体积  ,价值
int f[N][N];    // f[i][j] : 表示前 i 个 总体积不超过j
int n,m;

int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++) scanf("%d%d",&v[i],&w[i]);
    //f[0][0~m] =0 
    
    for(int i=1;i<=n;i++) 
        for(int j=0;j<=m;j++)
        {
            f[i][j]= f[i-1][j];
            if(j>=v[i]) f[i][j] = max(f[i-1][j],f[i-1][j-v[i]]+w[i]);
        }
    cout<<f[n][m]<<endl;
     
    
    
    return 0;
}

一维
#include<iostream>
#include<algorithm>

using namespace std;

const int N =1010;

int n,m;
int v[N],w[N];
int f[N];

int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>v[i]>>w[i];
    
    for(int i=1;i<=n;i++)
        for(int j=m;j>=v[i];j--)
            f[j]= max(f[j],f[j-v[i]]+w[i]);
        
    cout<<f[m];
    return 0;
}

完全背包 —— 每种物品都有无限件可用。

二维

状态方程:

  • 完全背包: f[i][j]= max(f[i][j],f[i][j-v[i]]+w[i]);
  • 0 1背包:f[i][j]= max(f[i][j],f[i-1][j-v[i]]+w[i]);
#include<iostream>
#include<algorithm>

using namespace std;

const int N =1010;

int  n,m;
int v[N],w[N];
int f[N][N];

int main(){
    
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>v[i]>>w[i];
    
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
          {
              f[i][j]=f[i-1][j];
              if(j>=v[i])
              f[i][j]= max(f[i][j],f[i][j-v[i]]+w[i]);
          }
    cout<<f[n][m]<<endl;      
    return 0;
}
一维
#include<iostream>
#include<algorithm>
using namespace std;

const int N=1010;

int n,m;
int v[N],w[N];
int f[N];

int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>v[i]>>w[i];
    
    for(int i=1;i<=n;i++)
        for(int j=v[i];j<=m;j++)
              f[j]=max(f[j],f[j-v[i]]+w[i]);
          
    cout<<f[m];
    return  0;
}

多重背包——第 i 种物品最多有 si 件

暴力写法

状态表示:
f[i][j]: 在前i个数中选,总体积不超过j;

状态计算:
f[i][j] = max(f[i][j],f[i-1][j-v[i]*k]+w[i]*k); (k:0~该数最多取几个)

#include<iostream>
#include<algorithm>

using namespace std;
const int N =110;

int n,m;
int v[N],w[N],s[N];
int f[N][N];

int main(){
    
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>v[i]>>w[i]>>s[i];
    
    for(int i=1;i<=n;i++)
        for(int j=0;j<=m;j++)
            for(int k=0;k<=s[i]&&k*v[i]<=j;k++)
                f[i][j] = max(f[i][j],f[i-1][j-v[i]*k]+w[i]*k);
    
    cout<<f[n][m]<<endl;            
    return 0;
}
二进制优化写法
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 12010, M = 2010;

int n, m;
int v[N], w[N];
int f[M];

int main()
{
    cin >> n >> m;

    int cnt = 0;
    for (int i = 1; i <= n; i ++ )
    {
        int a, b, s;
        cin >> a >> b >> s;
        int k = 1;
        while (k <= s) // k取 1,2,4,8.……,  <=s
        {
            cnt ++ ;
            v[cnt] = a * k;
            w[cnt] = b * k;
            s -= k;
            k *= 2;
        }
        if (s > 0)   // s还有就直接放进去
        {
            cnt ++ ;
            v[cnt] = a * s;
            w[cnt] = b * s;
        }
    }

    n = cnt;
    
    //01背包
    for (int i = 1; i <= n; i ++ )
        for (int j = m; j >= v[i]; j -- )
            f[j] = max(f[j], f[j - v[i]] + w[i]);

    cout << f[m] << endl;

    return 0;
}

 

分组背包——每组物品有若干个,同一组内的物品最多只能选一个。


#include <iostream>
#include <algorithm>

using namespace std;

const int N = 110;

int n, m;
int v[N][N], w[N][N], s[N];
int f[N];

int main()
{
    cin >> n >> m;

    for (int i = 1; i <= n; i ++ )
    {
        cin >> s[i];
        for (int j = 0; j < s[i]; j ++ )
            cin >> v[i][j] >> w[i][j];   // 体积是 vij,价值是 wij,其中 i 是组号,j 是组内编号。
    }

    for (int i = 1; i <= n; i ++ )
        for (int j = m; j >= 0; j -- )
            for (int k = 0; k < s[i]; k ++ )
                if (v[i][k] <= j)
                    f[j] = max(f[j], f[j - v[i][k]] + w[i][k]);

    cout << f[m] << endl;


    return 0;
}

背包问题中 的方案数问题

原始做法

#include <iostream>

using namespace std;

const int N = 10010, M = 110;
int f[N][N], a[M];

int main() {
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++) cin >> a[i];

    f[0][0] = 1;
    for (int i = 1; i <= n; i++) {
        f[i][0] = 1;
        for (int j = 1; j <= m; j++) {
            f[i][j] = f[i - 1][j];
            if (j >= a[i]) f[i][j] += f[i - 1][j - a[i]];
        }
    }
    cout << f[n][m] << endl;

    return 0;
}

优化空间

#include <iostream>

using namespace std;

const int N = 10010, M = 110;
int f[N], a[M];

int main() {
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++) cin >> a[i];

    f[0] = 1;
    for (int i = 1; i <= n; i++) {
        for (int j = m; j >= a[i]; j--) f[j] += f[j - a[i]];
    }
    cout << f[m] << endl;

    return 0;
}


线性DP

数字三角形

#include<bits/stdc++.h>

using namespace std;

const int N = 510;
int n;
int w[N][N];  // 原三角形数。
int f[N][N];  //f[i][j]: 自下向上 到达 f[i][j]的路径最大值
int main()
{ 
    cin>>n;

    for(int i=1;i<=n;i++)
        for(int j=1;j<=i;j++)
            cin>>w[i][j];  

    for(int j=1;j<=n;j++)
        f[n][j] = w[n][j];  // 对三角形最底层的数 初始化

    for(int i=n-1;i;i--)
        for(int j=1;j<=i;j++)
            f[i][j]=max(f[i+1][j]+w[i][j],f[i+1][j+1]+w[i][j]);   //自下向上推

    cout<<f[1][1]<<endl;


    return 0;
}

最长上升子序列

朴素写法
  • 状态方程 :if(a[j]<a[i]) f[i]=max(f[i],f[j]+1);
#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;
const int N=1010;
int f[N];
int a[N];
int n; 
int main(){
	 cin>>n;
	 for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	 
	 for(int i=1;i<=n;i++){
	 	f[i]=1;   // 初始只有a[i] 
		
		for(int j=1;j<i;j++)
		 	if(a[j]<a[i]) 
				f[i]=max(f[i],f[j]+1);
		 
	 }
	 
	 int res=1;
	 for(int i=1;i<=n;i++)res=max(res,f[i]);
	 
	 cout<<res;	
	 
	
	return 0;
} 
二分写法
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 100010;

int n;
int a[N];
int q[N];

int main()
{
    scanf("%d", &n);
    for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);

    int len = 0;
    for (int i = 0; i < n; i ++ )
    {
        int l = 0, r = len;
        while (l < r)
        {
            int mid = l + r + 1 >> 1;
            if (q[mid] < a[i]) l = mid;
            else r = mid - 1;
        }
        len = max(len, r + 1);
        q[r + 1] = a[i];
    }

    printf("%d\n", len);

    return 0;
}
 

最长公共子序列

  • 集合表示:f[i][j]表示a的前i个字母,和b的前j个字母的最长公共子序列长度

  • 集合划分:以a[i],b[j]是否包含在子序列当中为依据,因此可以分成四类:

#include <iostream>

using namespace std;

const int N = 1010;

int n , m;
char a[N] , b[N];
int f[N][N];
int main()
{
    cin >> n >> m;
    cin >> a + 1 >> b + 1;

    for(int i = 1 ; i <= n ; i++)
        for(int j = 1 ; j <= m ; j++)
            {
                f[i][j] = max(f[i - 1][j] , f[i][j - 1]);//②和③的情况一定存在,所以可以无条件优先判断
                if(a[i] == b[j]) f[i][j] = max(f[i][j] , f[i - 1][j - 1] + 1);
            }                                                       

    cout << f[n][m] << endl;
    return 0;
}
 

区间DP

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
const int N = 310;

int f[N][N]; // f[i][j]: 在(i,j)区间的最小代价
int s[N];
int n;

int main()
{
    cin>>n;
    for (int i = 1; i <= n; i ++ )cin>>s[i],s[i]+=s[i-1];
    
    for (int len = 2; len <= n; len ++ ){
        for (int i = 1; i+len-1 <= n; i ++ ){
            int l = i;
            int r = l+len-1;
            f[l][r]=1e8;
            for (int k = l; k <=r; k ++ ){
                f[l][r] = min(f[l][r],f[l][k]+f[k+1][r]+s[r]-s[l-1]);
            }
        }
    }
    cout<<f[1][n];
    return 0;
}

记忆化搜索

  • 例题 : 滑雪场
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 310;

int n, m;
int g[N][N];
int f[N][N];

int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};

int dp(int x, int y)
{
    int &v = f[x][y];
    if (v != -1) return v;

    v = 1;
    for (int i = 0; i < 4; i ++ )
    {
        int a = x + dx[i], b = y + dy[i];
        if (a >= 1 && a <= n && b >= 1 && b <= m && g[x][y] > g[a][b])
            v = max(v, dp(a, b) + 1);
    }

    return v;
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= m; j ++ )
            scanf("%d", &g[i][j]);

    memset(f, -1, sizeof f);

    int res = 0;
    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= m; j ++ )
            res = max(res, dp(i, j));

    printf("%d\n", res);

    return 0;
}

杂论补充

贪心

区间问题
区间选点
  • 给定 N 个闭区间 [ai,bi] ,请你在数轴上选择尽量少的点,使得每个区间内至少包含一个选出的点。
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;


const int N = 100010;

struct Range{    // 区间的结构体
  int l,r;
  bool operator<(const Range &w)const{   // 重载小于运算符: 为了sort用

      return r<w.r;
  }

}range[N];

int n,a,b;
int main()
{   
    cin>>n;
    for (int i = 0; i < n; i ++ )
    {
        scanf("%d%d", &a, &b);
        range[i]={a,b};
    } 

    sort(range,range+n); // 按右端点排序(小到大)

    int res=0,ed=-2e9;   // ed : 区间端点,因为刚开始还没有设置 。所以设置非常小的数
    for (int i = 0; i < n; i ++ )
    {
        if(range[i].l>ed)   // 如果当前区间的左端点在选出点的右边,说明当前区间和之前区间不重合, 需要个数++。 然后把选出点,设置为当前区间的右端点。
        {
            res++;
            ed=range[i].r;
        }
    }

    cout << res;
    return 0;

 
最大不相交的区间数量
  • 给定 N 个闭区间 [ai,bi],请你在数轴上选择若干区间,使得选中的区间之间互不相交(包括端点)。

    输出可选取区间的最大数量。

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 100010;

struct Range{
  int l,r;
  bool operator<(const Range &w)const{
      return r<w.r;
  }
}range[N];

int n;
int a,b;
int main()
{
    cin>>n;
    for (int i = 0; i < n; i ++ ){
        cin>>a>>b;
        range[i]={a,b};
    }

    sort(range,range+n);

    int res =0,ed=-2e9;
    for (int i = 0; i < n; i ++ ){
        if(range[i].l>ed){
            res++;
            ed=range[i].r;
        }

    }
    cout<<res;
    return 0;
}

区间分组
  • 给定 N 个闭区间 [ai,bi],请你将这些区间分成若干组,使得每组内部的区间两两之间(包括端点)没有交集,并使得组数尽可能小。
#include <iostream>
#include <algorithm>
#include <queue>

using namespace std;

const int N = 100010;

int n;
struct Range
{
    int l, r;
    bool operator< (const Range &W)const
    {
        return l < W.l;
    }
}range[N];

int main()
{
    scanf("%d", &n);
    for (int i = 0; i < n; i ++ )
    {
        int l, r;
        scanf("%d%d", &l, &r);
        range[i] = {l, r};
    }

    sort(range, range + n);

    priority_queue<int, vector<int>, greater<int>> heap;
    for (int i = 0; i < n; i ++ )
    {
        auto r = range[i];
        if (heap.empty() || heap.top() >= r.l) heap.push(r.r);
        else
        {
            heap.pop();
            heap.push(r.r);
        }
        
    }

    printf("%d\n", heap.size());

    return 0;
}

 
区间覆盖
  • 给定 N 个闭区间 [a**i,b**i] 以及一个线段区间 [s,t],请你选择尽量少的区间,将指定线段区间完全覆盖。

    输出最少区间数,如果无法完全覆盖则输出 −1。

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 100010;

int n;
struct Range
{
    int l, r;
    bool operator< (const Range &W)const
    {
        return l < W.l;
    }
}range[N];

int main()
{
    int st, ed;
    scanf("%d%d", &st, &ed);
    scanf("%d", &n);
    for (int i = 0; i < n; i ++ )
    {
        int l, r;
        scanf("%d%d", &l, &r);
        range[i] = {l, r};
    }

    sort(range, range + n);

    int res = 0;
    bool success = false;
    for (int i = 0; i < n; i ++ )
    {
        int j = i, r = -2e9;
        while (j < n && range[j].l <= st)
        {
            r = max(r, range[j].r);
            j ++ ;
        }

        if (r < st)
        {
            res = -1;
            break;
        }

        res ++ ;
        if (r >= ed)
        {
            success = true;
            break;
        }

        st = r;
        i = j - 1;
    }

    if (!success) res = -1;
    printf("%d\n", res);

    return 0;
}

 
哈夫曼树——合并果子

合并任意两堆

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;

int n,x;
priority_queue<int, vector<int>,greater<int>>heap;

int main()
{
    cin >> n;
    while (n -- )cin>>x,heap.push(x);
    int res=0;    
    while(heap.size()>1){
        int a = heap.top();heap.pop();
        int b = heap.top();heap.pop();
        res+=(a+b);
        heap.push(a+b);
    }
    cout << res;
    return 0;
}

 
绝对值不等式——货场选址
  • 在一条数轴上有 N 家商店,它们的坐标分别为 A1∼AN。现在需要在数轴上建立一家货仓,每天清晨,从货仓到每家商店都要运送一车商品。

    为了提高效率,求把货仓建在何处,可以使得货仓到每家商店的距离之和最小。


结论 : if(n == 奇数)选 中位数 else 选 中间两数中间 (记得排序)

注:中位数 不管是奇数还是偶数 ,都可以写做a[n/2]

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

int n;
int a[100010];
int main(){
    cin >> n;
    for (int i = 0; i < n; i ++ )scanf("%d",&a[i]);
    
    sort(a,a+n);
    
    int res=0;
    for (int i = 0; i < n; i ++ ) res+=abs(a[i]-a[n/2]);
    cout << res;
    return 0;
}

数论

约数个数
  • 给定 n 个正整数 ai,请你输出这些数的乘积的约数个数,答案对 1e9+7 取模。
/*
    如果 N = p1^c1 * p2^c2 * ... *pk^ck
    约数个数: (c1 + 1) * (c2 + 1) * ... * (ck + 1)
    约数之和: (p1^0 + p1^1 + ... + p1^c1) * ... * (pk^0 + pk^1 + ... + pk^ck)

*/
#include<iostream>
#include<unordered_map>
using namespace std;

typedef long long LL;

const int N=110,mod=1e9+7;

int main(){
    int n;
    cin>>n;

    unordered_map<int,int>primes;

    while(n--){
        int x;
        cin>>x;

        for(int i=2;i<=x/i;i++){
            while(x%i==0){
                x/=i;
                primes[i]++;
            }
        }
        if(x>1)primes[x]++;
    }   
    LL res=1;
    for(auto p:primes)res=res*(p.second+1)%mod;

    cout<<res<<endl;

    return 0;
}

 
约数之和
  • 给定 n 个正整数 ai,请你输出这些数的乘积的约数之和,答案对 1e9+7 取模。

/*
    如果 N = p1^c1 * p2^c2 * ... *pk^ck
    约数个数: (c1 + 1) * (c2 + 1) * ... * (ck + 1)
    约数之和: (p1^0 + p1^1 + ... + p1^c1) * ... * (pk^0 + pk^1 + ... + pk^ck)

*/
#include<iostream>
#include<unordered_map>
using namespace std;

typedef long long LL;

const int N=110,mod=1e9+7;

int main(){
    int n;
    cin>>n;

    unordered_map<int,int>primes;

    while(n--){
        int x;
        cin>>x;

        for(int i=2;i<=x/i;i++){
            while(x%i==0){
                x/=i;
                primes[i]++;
            }
        }
        if(x>1)primes[x]++;
    }   
    /* 约数个数 
    LL res=1;
    for(auto p:primes)res=res*(p.second+1)%mod;

    cout<<res<<endl;
    */

    /*约数之和 */ 


    LL res = 1;
    for (auto p : primes)
    {
        LL a = p.first, b = p.second;
        LL t = 1;
        while (b -- ) t = (t * a + 1) % mod;
        res = res * t % mod;
    }

    cout << res << endl;
    return 0;
}

 

搜索进阶

Flood Fill
连通块的个数
  • 池塘计数
#include <cstring>
#include <iostream>
#include <algorithm>

#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;

const int N = 1010, M = N * N;

int n, m;
char g[N][N];
PII q[M];
bool st[N][N];

void bfs(int sx, int sy)
{
    int hh = 0, tt = 0;
    q[0] = {sx, sy};
    st[sx][sy] = true;

    while (hh <= tt)
    {
        PII t = q[hh ++ ];

        for (int i = t.x - 1; i <= t.x + 1; i ++ )
            for (int j = t.y - 1; j <= t.y + 1; j ++ )
            {
                if (i == t.x && j == t.y) continue;
                if (i < 0 || i >= n || j < 0 || j >= m) continue;
                if (g[i][j] == '.' || st[i][j]) continue;

                q[ ++ tt] = {i, j};
                st[i][j] = true;
            }
    }
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i ++ ) scanf("%s", g[i]);

    int cnt = 0;
    for (int i = 0; i < n; i ++ )
        for (int j = 0; j < m; j ++ )
            if (g[i][j] == 'W' && !st[i][j])
            {
                bfs(i, j);
                cnt ++ ;
            }

    printf("%d\n", cnt);

    return 0;
}

 

红与黑
  • BFS
#include<bits/stdc++.h>
using namespace std;

typedef pair<int,int> PII;
#define x first
#define y second

int m,n;
char g[25][25];

int bfs(int sx,int sy)
{
	queue<PII>q;
	q.push({sx,sy}); // @ 坐标  入队。
	g[sx][sy]='#'; // 入队后 ,标记已走过。
	int res=0;
	           //偏移量 : {上,右,下,左} 
	int dx[]={-1,0,1, 0}; //行方向 
	int dy[]={ 0,1,0,-1}; //列方向
	
	while(q.size()) 
	{
		PII t= q.front();
		q.pop();
		res++;
		
		for(int i=0;i<4;i++) //遍历 四个方向的邻点 
		{
			int x=t.x+dx[i],y=t.y+dy[i];
			if(x<0||x>=n||y<0||y>=m||g[x][y]!='.')continue;
			g[x][y]='#';
			q.push({x,y});
		 } 
	}
		
	return res;
}
int main()
{ 
	while(cin>>m>>n,n||m)  // m  列  n  行 
	{
		for(int i=0;i<n;i++) cin>>g[i]; //输入n行字符串
		int x,y;// @ 所在位置的坐标
		
		for(int i=0;i<n;i++)         // 寻找 @的所在位置 
			for(int j=0;j<m;j++)
	 			if(g[i][j]=='@')
	 			{
				   x=i;y=j;
				} 
				
		cout<<bfs(x,y)<<endl;		
		 
	}
       
  return 0;
}
  • dfs

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 25;

int n, m;
char g[N][N];
bool st[N][N];

int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};

int dfs(int x, int y)
{
    int cnt = 1;

    st[x][y] = true;
    for (int i = 0; i < 4; i ++ )
    {
        int a = x + dx[i], b = y + dy[i];
        if (a < 0 || a >= n || b < 0 || b >= m) continue;
        if (g[a][b] != '.') continue;
        if (st[a][b]) continue;

        cnt += dfs(a, b);
    }

    return cnt;
}

int main()
{
    while (cin >> m >> n, n || m)
    {
        for (int i = 0; i < n; i ++ ) cin >> g[i];

        int x, y;
        for (int i = 0; i < n; i ++ )
            for (int j = 0; j < m; j ++ )
                if (g[i][j] == '@')
                {
                    x = i;
                    y = j;
                }

        memset(st, 0, sizeof st);
        cout << dfs(x, y) << endl;
    }

    return 0;
}

 
DFS
排列数字
#include<bits/stdc++.h>
using namespace std;

const int N=10;
int a[N];
bool st[N];  // 记录 哪些数是用过的
int n;

void dfs(int x)
{
    if(x==n)
    {
        for(int i=0;i<n;i++) printf("%d ",a[i]);        
        puts("");
        return;
    }
                                      // 之所以 i 从 0, 是因为 x 是从 0 开始的
    for(int i=0;i<n;i++) 
    {
        if(!st[i])
        {
            st[i]=true; // 标记

            a[x]=i+1;
            dfs(x+1);

            st[i]=false; // 恢复现场。 
        }
    }
}

int main()
{
    cin>>n;
    dfs(0);
    return 0;
 } 

 
n-皇后问题
#include<bits/stdc++.h>
using namespace std;

const int N=10;
int col[N],ug[2*N],dug[2*N];
bool st[N];
char a[N][N];
int n;

void Dfs(int x)
{
    if(x==n)
    {
        for(int i=0;i<n;i++)
        {
           puts(a[i]);
        //    puts("");
        }
        puts("");
        return;
    }
    for(int i=0;i<n;i++)
    {                                      
                                           /*
                                          dug[y-x+n]: y = x + b ----> b = y - x (由于y-x 可能是负)--->  b = y - x +n
                                          ug[i+x]  :  y = -x+b ------> b = y + x


                                           */
        if(!col[i]&&!ug[i+x]&&!dug[i-x+n])
         {
            col[i]=ug[i+x]=dug[i-x+n]=1;
            a[x][i]='Q';
            Dfs(x+1);
             col[i]=ug[i+x]=dug[i-x+n]=0;
             a[x][i]='.';
         }

    }

}
int main()
{

    cin>>n;
    for (int i = 0; i < n; i ++ )
        for (int j = 0; j < n; j ++ )
            a[i][j] = '.';
    Dfs(0);
    return 0;
}

 

        a[x]=i+1;
        dfs(x+1);

        st[i]=false; // 恢复现场。 
    }
}

}

int main()
{
cin>>n;
dfs(0);
return 0;
}


###### n-皇后问题

```cpp
#include<bits/stdc++.h>
using namespace std;

const int N=10;
int col[N],ug[2*N],dug[2*N];
bool st[N];
char a[N][N];
int n;

void Dfs(int x)
{
    if(x==n)
    {
        for(int i=0;i<n;i++)
        {
           puts(a[i]);
        //    puts("");
        }
        puts("");
        return;
    }
    for(int i=0;i<n;i++)
    {                                      
                                           /*
                                          dug[y-x+n]: y = x + b ----> b = y - x (由于y-x 可能是负)--->  b = y - x +n
                                          ug[i+x]  :  y = -x+b ------> b = y + x


                                           */
        if(!col[i]&&!ug[i+x]&&!dug[i-x+n])
         {
            col[i]=ug[i+x]=dug[i-x+n]=1;
            a[x][i]='Q';
            Dfs(x+1);
             col[i]=ug[i+x]=dug[i-x+n]=0;
             a[x][i]='.';
         }

    }

}
int main()
{

    cin>>n;
    for (int i = 0; i < n; i ++ )
        for (int j = 0; j < n; j ++ )
            a[i][j] = '.';
    Dfs(0);
    return 0;
}

 

标签:const,int,必备,cin,ACM,++,using,include,模板
来源: https://blog.csdn.net/weixin_46339668/article/details/121643820

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有