小猴编程周赛C++ | 2022年春第12周T1护城河

学习C++从娃娃抓起!记录下在学而思小猴编程学习过程中的题目,记录每一个瞬间。侵权即删,谢谢支持!

附上汇总贴:小猴编程C++ | 汇总-CSDN博客


【题目描述】

xy平面上有若干个村子。为了保护所有村子,你要修建一条护城河。

给出一个4×4的二维数组A, A i , j A_{i,j} Ai,j表示在坐标(i−0.5,j−0.5)处有一个村子。

护城河是一个多边形,满足如下条件:

(1)自己的边不在端点以外的地方相交。

(2)所有村子都在多边形内部。

(3)所有顶点的坐标都是0∼4的整数。

(4)所有边都与x轴或y轴平行。

(5)所有内角都是90度或270度。

你想要护城河越短越好,求护城河的最短周长,以及修建最短周长护城河的方法数。

【输入】

4行4列,共16个值为0或1的整数,表示村子的位置。

若第i行第j列为1,表示坐标(i−0.5,j−0.5)处有一个村子。

【输出】

两个整数,第1个表示护城河的最短周长,第2个表示修建最短护城河的方法数。

【输入样例】

1 0 0 0
0 0 1 0
0 0 0 0
1 0 0 0

【输出样例】

14 18

【代码详解】

#include <bits/stdc++.h>
using namespace std;
bool a[10][10], c[10][10], flag[10][10];
//a[i][j]为1表示有村子
//c[i][j]为1表示在护城河内
//flag[i][j]表示从1个村子能染色到的点
int ans = 1e9, cnt, sx, sy;
int cal()
{
    int ans = 0;
    for (int i=1; i<=4; i++)
        for (int j=1; j<=4; j++) {
            if (c[i][j]) {
                ans += 4;
                if (c[i+1][j]) ans--;
                if (c[i-1][j]) ans--;
                if (c[i][j+1]) ans--;
                if (c[i][j-1]) ans--;
            }
        }
    return ans;
}
void ddd(int x, int y)
{
    if (x<1 || x>4 || y<1 || y>4) return;
    if (c[x][y]==false) return;
    if (flag[x][y]) return;
    flag[x][y] = true;
    ddd(x-1, y);
    ddd(x+1, y);
    ddd(x, y+1);
    ddd(x, y-1);
}
bool check()
{
    for (int i=1; i<=4; i++)
        for (int j=1; j<=4; j++) 
            if (a[i][j]==1 && c[i][j]==0) return false;
    memset(flag, 0, sizeof(flag));

    ddd(sx, sy);
    for (int i=1; i<=4; i++)
        for (int j=1; j<=4; j++)
            if (c[i][j]==1 && flag[i][j]==0) return false;
    return true;
}
void dfs(int x, int y)
{
    if (y>4) {
        y=1; 
        x++;
    }
    if (x>4) {
        if (check()) {
            int sum = cal();
            if (sum==ans) cnt++;
            if (sum<ans) {
                ans = sum;
                cnt = 1;
            }
        }
        return;
    }
    c[x][y] = 0;
    dfs(x, y+1);
    c[x][y] = 1;
    dfs(x, y+1);
}
int main()
{
    for (int i=1; i<=4; i++)
        for (int j=1; j<=4; j++) {
            cin >> a[i][j];
            if (sx==0 && a[i][j]==1) {
                sx = i;
                sy = j;
            }
        }
    dfs(1, 1);
    cout << ans << " " << cnt << endl;
    return 0;
}

【运行结果】

1 0 0 0
0 0 1 0
0 0 0 0
1 0 0 0
14 18
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值