算法分析与设计 西工大 noj 第二次实验

算法分析与设计 西工大 noj 第二次实验

Problem A 0-1背包问题

时限:1000ms 内存限制:10000K 总时限:3000ms

描述:

需对容量为c 的背包进行装载。从n 个物品中选取装入背包的物品,每件物品i 的重量为wi ,价值为pi 。对于可行的背包装载,背包中物品的总重量不能超过背包的容量,最佳装载是指所装入的物品价值最高。

输入:

多个测例,每个测例的输入占三行。第一行两个整数:n(n<=10)和c,第二行n个整数分别是w1到wn,第三行n个整数分别是p1到pn。
n 和 c 都等于零标志输入结束。

输出:

每个测例的输出占一行,输出一个整数,即最佳装载的总价值。

输入样例:

1 2
1
1
2 3
2 2
3 4
0 0

输出样例:

1
4

这是一道典型的01背包。由于n十分小,所以可以采用暴力搜索,也可以采用DP。

其实严格意义上我完全可以把物品的价值搞成1e9,这样就不可以使用DP了,但是数据十分水,也就过去了。

标准解法是暴力

#include <iostream>
#include <cstdio>
using namespace std;
#define N 20
int n, m;
int w[N], v[N];
int ans = 0;
inline int max(int x, int y)
{
    return x > y ? x : y;
}
void dfs(int x, int sw, int sv)
{
    if(x > n) {
        ans = max(ans, sw);
        return;
    }
    dfs(x+1, sw, sv);

    if(sv + v[x] <= m){
        dfs(x+1, sw + w[x], sv+v[x]);
    }
}
int main()
{
    while(scanf("%d%d", &n, &m), n||m)
    {
        ans = 0;
        for(int i = 1; i <= n; i++) scanf("%d", v+i);
        for(int i = 1; i <= n; i++) scanf("%d", w+i);

        dfs(1, 0, 0);
        printf("%d\n", ans);
    }
    return 0;
}

Problem B 装载问题

时限:1000ms 内存限制:10000K 总时限:3000ms

描述:

有两艘船,载重量分别是c1、 c2,n个集装箱,重量是wi (i=1…n),且所有集装箱的总重量不超过c1+c2。确定是否有可能将所有集装箱全部装入两艘船。

输入:

多个测例,每个测例的输入占两行。第一行一次是c1、c2和n(n<=10);第二行n个整数表示wi (i=1…n)。n等于0标志输入结束。

输出:

对于每个测例在单独的一行内输出Yes或No。

输入样例:

7 8 2
8 7
7 9 2
8 8
0 0 0

输出样例:

Yes
No

其实本质上还是一道背包问题。

把第一个小船当成背包,在不超载的前提下放置尽可能重的物品,以便于为第二艘小船留下余地。

#include<iostream>
#include<cstdio>
using namespace std;
#define N 20
int c1, c2, n;
int w[N];
int sum;
bool flag = false;
void dfs(int x, int s)
{
    if(x > n){
        if(s <= c1 && (sum - s) <= c2) flag = true;
        return ;
    }
    dfs(x+1, s);
    dfs(x+1, s+w[x]);
}
int main()
{
    while(scanf("%d%d%d", &c1, &c2, &n), n)
    {
        flag = false;
        sum = 0;
        for(int i = 1; i <= n; i++) scanf("%d", w+i);
        for(int i = 1; i <= n; i++) sum += w[i];
        dfs(1, 0);
        if(flag)
        {
            puts("Yes");
        }
        else
        {
            puts("No");
        }
    }
    return 0;
}

Problem C 堡垒问题

时限:1000ms 内存限制:10000K 总时限:3000ms

描述:

城堡是一个4×4的方格,为了保卫城堡,现需要在某些格子里修建一些堡垒。城堡中的某些格子是墙,其余格子都是空格,堡垒只能建在空格里,每个堡垒都可以向上下左右四个方向射击,如果两个堡垒在同一行或同一列,且中间没有墙相隔,则两个堡垒都会把对方打掉。问对于给定的一种状态,最多能够修建几个堡垒。

输入:

每个测例以一个整数n(1<=n<=4)开始,表示城堡的大小。接下来是n行字符每行n个,‘X’表示该位置是墙,‘.’表示该位置是空格。n等于0标志输入结束。

输出:

每个测例在单独的一行输出一个整数:最多修建堡垒的个数。

输入样例:

4
.X..
....
XX..
....
2
XX
.X
3
.X.
X.X
.X.
3
...
.XX
.XX
4
....
....
....
....
0

输出样例:

5
1
5
2
4
#include <cstdio>
#include <cstdlib>
using namespace std;
#define N 6
char a[N][N];
int n;
int ans = 0;
inline void get(int val, int &x, int &y)
{
    x = val/n;
    y = val%n;
}
bool ck(int x, int y)
{
    for(int i = x+1; i < n; i++){
        if(a[i][y] == 'o') return 0;
        else if(a[i][y] == 'X') break;
    }
    for(int i = x-1; i >= 0; i--){
        if(a[i][y] == 'o') return 0;
        else if(a[i][y] == 'X') break;
    }
    for(int i = y+1; i< n; i++){
        if(a[x][i] == 'o') return 0;
        else if(a[x][i] == 'X') break;
    }
    for(int i = y-1; i >= 0; i--){
        if(a[x][i] == 'o') return 0;
        else if(a[x][i] == 'X') break;
    }
    return true;
}
void dfs(int p, int s)
{
    if(p >= n*n){
        if(s > ans) ans = s;
        //DEBUG
        /*
        if(s == 4){
            for(int i = 0; i < 4; i++)
            {
                for(int j = 0; j < 4; j++)
                {
                    printf("%c", a[i][j]);
                }
                puts("");

            }
            puts("");
        }
        */
        //ENDDEBUG
        return ;
    }

    dfs(p+1, s);
    int x, y;
    get(p, x, y);
    if(ck(x, y) && a[x][y] == '.')
    {
        a[x][y] = 'o';
        dfs(p+1, s+1);
        a[x][y] = '.';
    }
}
int main()
{
    while(scanf("%d", &n), n){
        for(int i = 0; i < n; i++) scanf("%s", a[i]);
        ans = 0;
        dfs(0, 0);
        printf("%d\n", ans);
    }
    // n = 4;
    // for(int i = 0; i < 16; i++)
    // {
    //     int x, y;;
    //     get(i, x, y);
    //     printf("(%d, %d)  ", x, y);
    // }

}

Problem D 8皇后问题

时限:1000ms 内存限制:10000K 总时限:3000ms

描述:

输出8皇后问题所有结果。

输入:

没有输入。

输出:

每个结果第一行是No n:的形式,n表示输出的是第几个结果;下面8行,每行8个字符,‘A’表示皇后,‘.’表示空格。不同的结果中,先输出第一个皇后位置靠前的结果;第一个皇后位置相同,先输出第二个皇后位置靠前的结果;依次类推。

输入样例:

输出样例:

输出的前几行:
No 1:
A.......
....A...
.......A
.....A..
..A.....
......A.
.A......
...A....
No 2:
A.......
.....A..
.......A
..A.....
......A.
...A....
.A......
....A...

这一道题目所使用的数据结构十分巧妙,由于每一行仅仅只可以有一个皇后,所以采用一维数组就可以。

注意时时刻刻想着剪枝。

判断对角线的方法是:abs(stac[i] - val) == abs(i-row)

#include <cstdio>
#include <algorithm>
#include <cstdlib>
using namespace std;
#define N 12
int stac[N];
int cnt = 0;
bool ck(int row, int val)
{
    for(int i = 1; i <= 8; i++)
    {
        if(stac[i] == 0 || i == row) continue;
        if(stac[i] == val || abs(stac[i] - val) == abs(i-row)) return false;
    }
    return true;
}
inline void Print(int x)
{
    for(int i = 1; i < x; i++) putchar('.');
    putchar('A');
    for(int i = x+1; i <= 8; i++) putchar('.');
    puts("");
} 
void dfs(int x)
{
    if(x > 8)
    {
        printf("No %d:\n", ++cnt);
        for(int i = 1; i <= 8; i++)
        {
            Print(stac[i]);
        }
        return;
        // for(int i = 1; i <= 8; i++) printf("%d ", stac[i]);
        //balabala
        //return ;
        //DEBUG
        // exit(0);
    }
    for(int i = 1; i <= 8; i++)
    {
        if(ck(x, i)) {
            stac[x] = i;
            dfs(x+1);
            stac[x] = 0;
        }
    }
}
int main()
{
    dfs(1);
    return 0;
}

Problem E 素数环问题

时限:1000ms 内存限制:10000K 总时限:3000ms

描述:

把1到20这重新排列,使得排列后的序列A满足:
a. 任意相邻两个数之和是素数
b. 不存在满足条件a的序列B使得:A和B的前k(0 <= k <= 19)项相同且B的第k+1项比A的第k+1项小。(即按字典序排列的第一项)

输入:

没有输入。

输出:

输出A,两个数字之间用一个空格隔开,第一个数字前面和最后一个数字后面没有空格。

输入样例:

输出样例:

标准解法

如果要是要求输出所有的素数环,那么就应该采用求全排列+剪枝+判断字典序

贪心解法

但是可以使用贪心来做。从前往后先试1,然后再试2…如果找到满足条件的环,就直接输出。

打表解法

这么小的数据量,直接人脑使用贪心法进行计算,来一个puts("")

//采取贪心的思想,从小到大选择
#include <cstdio>
#include <cstdlib>
using namespace std;
#define N 25
bool v[N];
int stac[N];
bool prim[40];
void dfs(int x)
{
    if(x > 20)
    {
        for(int i = 1; i <= 20; i++) {
            if(i != 20)
                printf("%d ", stac[i]);
            else printf("%d", stac[20]);
        }
        puts("");
        exit(0);
    }
    for(int i = 1; i <= 20; i++)
    {
        if(!v[i] && (x == 1 || x < 20 && x > 1 && (prim[stac[x-1] + i]) ||(x == 20 && (prim[stac[1] + i]))))
        {
            stac[x] = i;
            v[i] = 1;
            dfs(x+1);
            v[i] = 0;
            stac[x] = 0;
        }
    }
}
int main()
{   
    for(int i = 2; i <= 45; i++)
    {
        bool flag = true;
        for(int j = 2; j*j <= i; j++) if(i % j == 0){
            flag = false;
            break;
        }
        if(!flag) prim[i] = 0;
        else prim[i] = 1;
    }
    dfs(1);
    // for(int i = 1; i <= 45; i++) if(prim[i])
    //     printf("%d ", i);
    return 0;
}

Problem F 迷宫问题

时限:1000ms 内存限制:10000K 总时限:3000ms

描述:

给一个20×20的迷宫、起点坐标和终点坐标,问从起点是否能到达终点。

输入:

多个测例。输入的第一行是一个整数n,表示测例的个数。接下来是n个测例,每个测例占21行,第一行四个整数x1,y1,x2,y2是起止点的位置(坐标从零开始),(x1,y1)是起点,(x2,y2)是终点。下面20行每行20个字符,’.’表示空格;’X’表示墙。

输出:

每个测例的输出占一行,输出Yes或No。

输入样例:

2
0 0 19 19
....................
XXXXXXXXXXXXXXXXXXXX
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
0 0 19 19
....................
XXXXXXXXXXXXXXXXXXX.
....................
.XXXXXXXXXXXXXXXXXXX
....................
XXXXXXXXXXXXXXXXXXX.
....................
.XXXXXXXXXXXXXXXXXXX
....................
XXXXXXXXXXXXXXXXXXX.
....................
.XXXXXXXXXXXXXXXXXXX
....................
XXXXXXXXXXXXXXXXXXX.
XXXXXXXXXXXXXXXXXXX.
XXXXXXXXXXXXXXXXXXX.
XXXXXXXXXXXXXXXXXXX.
....................
.XXXXXXXXXXXXXXXXXXX
....................

输出样例:

No
Yes

直接进行DFS图的遍历

#include <iostream>
#include <cstdio>

using namespace std;
#define N 30
pair<int, int> s, t;
char a[N][N];
bool v[N][N];
const int n = 20;
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};
inline bool ck(int x, int y)
{
    if(x < 0 || x >= n || y < 0 || y >= n) return false;
    if(v[x][y]) return false;
    if(a[x][y] == 'X') return false;
    return true;
}
bool dfs(int nx, int ny)
{
    if(nx == t.first && ny == t.second){
        return 1;
    }
    for(int k = 0; k < 4; k++)
    {
        int x = nx + dx[k];
        int y = ny + dy[k];
        if(ck(x, y))
        {
            v[x][y] = 1;
            if(dfs(x, y)) return 1;
        }
    }
    return 0;
}
int main()
{
    int T;
    cin >> T;
    while(T--)
    {
        for(int i = 0; i <= 20; i++)
            for(int j = 0; j <= 20; j++)
                v[i][j] = false;
        scanf("%d%d%d%d", &s.first, &s.second, &t.first, &t.second);
        for(int i = 0; i < n; i++) scanf("%s", a[i]);
        if(dfs(s.first, s.second))
        {
            puts("Yes");
        }
        else
        {
            puts("No");
        }
    }
    return 0;   
}

Problem G 踩气球

时限:1000ms 内存限制:10000K 总时限:3000ms

描述:

六一儿童节,小朋友们做踩气球游戏,气球的编号是1~100,两位小朋友各踩了一些气球,要求他们报出自己所踩气球的编号的乘积。现在需要你编一个程序来判断他们的胜负,判断的规则是这样的:如果两人都说了真话,数字大的人赢;如果两人都说了假话,数字大的人赢;如果报小数字的人说的是真话而报大数字的人说谎,则报小数字的人赢(注意:只要所报的小数字是有可能的,即认为此人说了真话)。

输入:

输入为两个数字,0 0表示结束;

输出:

输出为获胜的数字。

输入样例:

36 62
49 343
0 0

输出样例:

62
49

这一道题目使我畏惧,真的是太太太离谱了!

暴力搜索法:

虽然看起来有很多情况,但是由于int范围内的相乘大于int的数字其实并没有多少,所以也还可以

#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;
int small, big;//大的数字以及小的数字
int mul1, mul2;//已经当前已经踩过的气球的乘积
bool f1, f2;//记录说的是不是真话

void dfs(int k)
{
    if(k <= 1){
        if(mul1 == small && mul2 == big) {
            f1 = 1, f2 = 1;
        }
        else if( (!f1 || !f2) && mul1 == small ){
            f1 = 1, f2 = 0;
        }
        else if(!f1&&!f2&&mul2 == big){
            f1 = 0, f2 = 1;
        }
        return ;
    }
    if(mul1*k <= small && small % k == 0){
        mul1 *= k;
        dfs(k-1);
        mul2 /= k;
    }
    if(mul2 * k <= big && big % k == 0){
        mul2 *= k;
        dfs(k-1);
        mul2 /= k;
    }
    dfs(k-1);
}
int main()
{

    while(scanf("%d%d", &big, &small), big || small){

        if(small > big) swap(small, big);
        mul1 = 1, mul2 = 1;
        f1 = 0, f2 = 0;
        dfs(100);
        if(f1 && f2 || !f1 && !f2){
            printf("%d\n", big);
        }
        else{
            if(f1) printf("%d\n", small);
            else printf("%d\n", big);
        }
    }
    //cout << f1 << f2;
    return 0;   
}

Problem H 字母转换

时限:1000ms 内存限制:10000K 总时限:3000ms

描述:

通过栈交换字母顺序。给定两个字符串,要求所有的进栈和出栈序列(i表示进栈,o表示出栈),使得字符串2在求得的进出栈序列的操作下,变成字符串1。输出结果需满足字典序。例如TROT 到 TORT:
[
i i i i o o o o
i o i i o o i o
]

输入:

给定两个字符串,第一个字符串是源字符串,第二个字符是目标目标字符串。

输出:

所有的进栈和出栈序列,输出结果需满足字典序

输入样例:

madam
adamm
bahama
bahama
long
short
eric
rice

输出样例:

[
i i i i o o o i o o 
i i i i o o o o i o 
i i o i o i o i o o 
i i o i o i o o i o 
]
[
i o i i i o o i i o o o 
i o i i i o o o i o i o 
i o i o i o i i i o o o 
i o i o i o i o i o i o 
]
[
]
[
i i o i o i o o 
]
#include <cstdio>
#include <iostream>
#include <stack>
#include <cstring>
#include <vector>
using namespace std;
#define N 100005
char a[N], b[N];
stack<char> st;
vector<char> op;
int p = 1;
int q = 1;
int len = 0;
void dfs(int n)
{
    if(n > 2 * len)
    {
        for(int i = 0; i < op.size(); i++)
        {
            if(i != op.size() - 1)
                printf("%c ", op[i]);
            else 
                printf("%c", op[i]);
        }
        puts("");
        return;
    }
    if(p <= len)
    {
        op.push_back('i');
        st.push(a[p]);
        p++;
        dfs(n+1);
        op.pop_back();
        st.pop();
        p--;
    }
    if(st.size() && st.top() == b[q])
    {
        op.push_back('o');
        char tmp = st.top();
        st.pop();
        q++;
        dfs(n+1);
        q--;
        st.push(tmp);
        op.pop_back();
    }
}
int main()
{
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);

    while(scanf("%s%s", a+1, b+1) != EOF)
    {
        int len1 = strlen(a+1);
        int len2 = strlen(b+1);
        if(len1 != len2){
            printf("[\n]\n");
            continue;
        }
        len = len1;
        printf("[\n");
        dfs(1);
        printf("]\n");
    }
    return 0;   
}

Problem I 农场灌溉问题

时限:1000ms 内存限制:10000K 总时限:3000ms

描述:

一农场由图所示的十一种小方块组成,蓝色线条为灌溉渠。若相邻两块的灌溉渠相连则只需一口水井灌溉。

输入:

给出若干由字母表示的最大不超过50×50具体由(m,n)表示,的农场图

输出:

编程求出最小需要打的井数。每个测例的输出占一行。当M=N=-1时结束程序。

输入样例:

2 2
DK
HF
3 3
ADC
FJK
IHE
-1 -1

输出样例:

2
3

简直是带模拟

需要注意判断可达性的时候,不仅仅与当前的格子有关系,并且与其他的格子有关系。

#include <iostream>
#include <cstdio>

using namespace std;

bool th[128][5];
int n,m;
char a[100][100];
bool v[100][100];
void init();
void dfs(int x, int y)
{
    v[x][y] = 1;
    int r, c;
    //0
    r = x, c = y-1;
    if(r >= 1 && r <= n && c >= 1 && c <= m && !v[r][c]){
        if(th[a[x][y]][0] && th[a[r][c]][2]){
            dfs(r, c);
        }
    } 
    //1
    r = x-1, c = y;
    if(r >= 1 && r <= n && c >= 1 && c <= m && !v[r][c]){
        if(th[a[x][y]][1] && th[a[r][c]][3]){
            dfs(r, c);
        }
    } 
    //2
    r = x, c = y+1;
    if(r >= 1 && r <= n && c >= 1 && c <= m && !v[r][c]){
        if(th[a[x][y]][2] && th[a[r][c]][0]){
            dfs(r, c);
        }
    } 
    //3
    r = x+1, c = y;
    if(r >= 1 && r <= n && c >= 1 && c <= m && !v[r][c]){
        if(th[a[x][y]][3] && th[a[r][c]][1]){
            dfs(r, c);
        }
    } 
}
int main()
{
    init();
    while(scanf("%d%d", &n, &m), n!=-1 || m!=-1)
    {
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++)
                v[i][j] = 0;
        for(int i = 1; i <= n; i++) scanf("%s", a[i] + 1);
        int ans = 0;
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++)
            {
                if(!v[i][j]) {
                    dfs(i, j);
                    ans ++;
                }
            }
        printf("%d\n", ans);
        // for(int i = 1; i <= n; i++)
        // {
        //     for(int j = 1; j <= m; j++)
        //         cout << a[i][j];
        //     puts("");
        // }
              
    }
    return 0;
}
void init()
{
    th['A'][0] = 1;
    th['A'][1] = 1;

    th['B'][1] = 1;
    th['B'][2] = 1;

    th['C'][0] = 1;
    th['C'][3] = 1;

    th['D'][2] = 1;
    th['D'][3] = 1;

    th['E'][1] = 1;
    th['E'][3] = 1;

    th['F'][0] = 1;
    th['F'][2] = 1;

    th['G'][0] = 1;
    th['G'][1] = 1;
    th['G'][2] = 1;

    th['H'][0] = 1;
    th['H'][1] = 1;
    th['H'][3] = 1;

    th['I'][0] = 1;
    th['I'][2] = 1;
    th['I'][3] = 1;

    th['J'][1] = 1;
    th['J'][2] = 1;
    th['J'][3] = 1;

    th['K'][0] = 1;
    th['K'][1] = 1;
    th['K'][2] = 1;
    th['K'][3] = 1;

}

Problem J 求图像的周长

时限:1000ms 内存限制:10000K 总时限:3000ms

描述:

给一个用 . 和X表示的图形,图形在上、下、左、右、左上、左下、右上、右下8个方向都被看作是连通的,并且图像中间不会出现空洞,求这个图形的边长。

image

输入:

首先给出m、n、x、y四个正整数,下面给出m×n的图形,x、y表示点击的位置,全0表示结束。

输出:

点击的图形的周长。

输入样例:

2 2 2 2
XX
XX
6 4 2 3
.XXX
.XXX
.XXX
...X
..X.
X...
0 0 0 0 

输出样例:

8
18
#include <iostream>
#include <cstdio>
using namespace std;
#define N 10005
int n, m, sx, sy;
char a[N][N]; 
bool v[N][N];
int ans = 0;
int dx[8] = {-1, -1, -1 ,0, 0, 1, 1, 1};
int dy[8] = {-1, 0, 1, -1, 1, -1, 0, 1};

int lenth(int nx, int ny)
{
    int all = 4;
    static const int qx[4] = {-1, 0, 0, 1};
    static const int qy[4] = {0, -1, 1, 0};
    for(int k = 0; k < 4; k++)
    {
        int x = nx + qx[k];
        int y = ny + qy[k];
        if(x < 1 || x > n || y < 0 || y > m) continue;
        if(a[x][y] == 'X')all --;
    }
    return all;
}

void dfs(int nx, int ny)
{
    v[nx][ny] = 1;
    ans += lenth(nx, ny);
    for(int k = 0; k < 8; k++)
    {
        int x = dx[k] + nx;
        int y = dy[k] + ny;
        if(v[x][y]) continue;
        if(a[x][y] != 'X') continue;
        dfs(x, y);
    }
}
int main()
{
    while(scanf("%d%d%d%d", &n, &m, &sx, &sy), n || m || sx || sy)
    {
        for(int i = 1; i <= n; i++) scanf("%s", a[i]+1);
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++)
                v[i][j] = 0;
        ans = 0;
        dfs(sx, sy);
        printf("%d\n", ans);
    }

    return 0;
}

Problem K 图的m着色问题

时限:1000ms 内存限制:10000K 总时限:3000ms

描述:

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

输入:

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

输出:

输出不同的着色方案的总数。

输入样例:

3 2 2
0 1
1 2

输出样例:

2
#include <iostream>
#include <cstdio>
using namespace std;
#define N 25
int a[N][N];
int c[N];
int n, r, m;
int ans = 0;
inline bool ck(int x, int val)
{
    for(int y = 1; y < x; y++)
    {
        if(!a[x][y]) continue;
        if(val == c[y]) return 0;
    }
    return true;
}
void dfs(int x)
{
    if(x > n){
        ans ++;
        // for(int i = 1; i <= n; i++) printf("%d ", c[i]);
        // puts("");
        return;
    }
    for(int i = 1; i <= m; i++)
    {
        if(ck(x, i)) {
            c[x] = i;
            dfs(x+1);
            c[x] = 0;//浅浅回复一下
        } 
    }
} 
int main()
{   
    scanf("%d%d%d", &n, &r, &m);
    for(int i = 1; i <= r; i++)
    {
        int u, v;
        scanf("%d%d", &u, &v);
        u++, v++;
        a[u][v] = 1;
        a[v][u] = 1;
    }
    dfs(1);
    printf("%d\n", ans);
    return 0;
}

Problem L 三阶幻方

时限:1000ms 内存限制:10000K 总时限:3000ms

描述:

三阶幻方是最简单的幻方,又叫九宫格,是由1,2,3,4,5,6,7,8,9九个数字组成的一个三行三列的矩阵,其对角线、横行、纵向的的和都为15。

输入:

输出:

按字典序输出所有的满足条件的幻方矩阵,每两个数字之间带一个空格,行尾无空格,每个幻方后带一个空行。

无输入以及输出样例

//幻方!都可以幻方!!!!
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
bool v[12];
int a[4][4];
inline bool judge(int x, int y, int val)
{
    //DEBUG
    //return true;
    int sum = 0;
    if(x == 0 && y == 2){
        for(int i = 0; i < 3; i++) sum += a[0][i];
        if(sum == 15) return true;
        else return false;
    }
    if(x == 1 && y == 2){
        for(int i = 0; i < 3; i++) sum += a[1][i];
        if(sum == 15) return true;
        else return false;
    }
    if(x == 2 && y == 0)
    {
        int s1 = 0, s2 = 0;;
        for(int i = 0; i < 3; i++) s1 += a[i][0];
        s2 += a[0][2] + a[1][1] + a[2][0];;
        if(s2 == 15 && s1 == 15) return true;
        else return false;
    }
    if(x == 2 && y == 1){
        for(int i = 0; i < 3; i++) sum += a[i][1];
        if(sum == 15) return true;
        else return false;
    }
    if(x == 2 && y == 2){
        int s1 = 0, s2 = 0, s3 = 0;
        for(int i = 0; i < 3; i ++) s1 += a[i][2];
        for(int i = 0; i < 3; i ++) s2 += a[i][i];
        for(int i = 0; i < 3; i ++) s3 += a[2][i];
        if(s1 == 15 && s2 == 15 && s3 == 15) return true;
        else return false;
    }
    return true;
}
    //int dede = 0;
void dfs(int p)
{
    if(p >= 3*3)
    {
        for(int i = 0; i < 3; i++)
        {
            for(int j = 0; j < 3; j++)
            {
                if(j < 2)
                    printf("%d ", a[i][j]);
                else
                    printf("%d", a[i][j]);
            }
            puts("");
        }
        puts("");
        //if(++dede >= 5) exit(0);
    }
    int nx = p/3;
    int ny = p%3;
    for(int i = 1; i <= 9; i++)
    {
        a[nx][ny] = i;
        if(judge(nx, ny, i) && !v[i]){
            v[i] = 1;
            dfs(p+1);
            v[i] = 0;
        }
        a[nx][ny] = 0;
    }
}
int main()
{
    dfs(0);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值