如何递归地解决USACO 2013-周长-银
How to solve USACO 2013-Perimeter-Silver Recursively
所以我正在解决这个 USACO 2013 年 2 月银色竞赛 - 周长 - 问题 1。
问题链接:问题链接
链接到此问题的青铜版本:问题链接
链接到解决方案:银牌 - 链接到解决方案 铜牌 - 链接到解决方案
问题:
问题1:周长[布莱恩·迪恩,2013]
农民约翰在中间安排了N个干草包(1 <= N <= 50,000( 他的领域之一。 如果我们将字段视为 1,000,000 x 1,000,000 1 x 1 方形单元格的网格,每个干草包恰好占据其中一个 牢房(当然,没有两个干草包占据同一个牢房(。
FJ注意到他的干草捆都形成了一个大的相连区域,这意味着 从任何一捆开始,人们可以通过采取 北、南、东或西到直接相邻的一系列台阶 包。 然而,干草捆的连接区域可能包含"洞"—— 完全草包包围的空旷区域。
请帮助FJ确定由他的干草形成的区域的周长 包。 请注意,孔不会对周长产生影响。
问题名称: 周长
输入格式:
-
第 1 行:干草包的数量,N。
-
第 2..1+N 行:每行包含单个干草的 (x,y( 位置 bale,其中 x 和 y 都是范围内的整数 1..1,000,000. 位置 (1,1( 是 FJ 的左下角单元格 字段和位置 (1000000,1000000( 是右上角的单元格。
示例输入(文件 perimeter.in(:
8
10005 200003
10005 200004
10008 200004
10005 200005
10006 200003
10007 200003
10007 200004
10006 200005
输入详细信息:
由干草捆组成的连接区域如下所示:
二十
十 二十
三十
输出格式:
- 1号线:干草捆连接区域的周长。
示例输出(文件外围(:
14
输出详细信息:
连接区域的周长为 14(例如, 该区域的左侧贡献了该总数的 3 长度(。 观察 中间的孔对这个数字没有贡献。
我做了什么
我继续对这个问题进行递归解决方案,如下所示:
#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
#include <map>
using namespace std;
#define rep(i,a,b) for(auto (i)=a;i<b;i++)
#define list(i,N) for(auto (i)=0;i<N;i++)
typedef long long ll;
typedef vector<ll> vi;
typedef pair<ll,ll> pi;
#define mp make_pair
#define pb push_back
#define int ll
#define INF 1e18+5
#define mod 1000000007
//One map for storing whether a cell has hay bale or not
//And the other for visited - whether a cell has been visited or not
map<pi,bool> vis;
map<pi,bool> exists;
int ans = 0;
void solve(int i, int j){
//Check about the visited stuff
if(vis[mp(i,j)]) return;
vis[mp(i,j)] = true;
//Find the answer now
ans += 4;
if(exists[mp(i-1,j)]){
--ans; solve(i-1,j);
}
if(exists[mp(i+1,j)]){
--ans; solve(i+1,j);
}
if(exists[mp(i,j+1)]){
--ans; solve(i,j+1);
}
if(exists[mp(i,j-1)]){
--ans; solve(i,j-1);
}
}
int32_t main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int N; cin >> N;
int first, second; //the starting point where we start the function...
while(N--){
int a,b; cin >> a >> b;
first = a; second = b; //in the end, it is just the coordinate specified in the last in the input...
exists[mp(a,b)] = true; //Hay Bale exists...
}
solve(first,second);
cout << ans << "n";
return 0;
}
基本上,我正在做的是:
从单元格开始。
首先,检查该单元格以前是否被访问过。如果是,请返回。如果没有,请访问它。
在计数器上加 4 的所有四个边。
环顾细胞,了解其所有相邻的细胞。如果单元格也有干草包,请从计数器中减去 1(无需添加边界(,然后转到 2。
我面临的问题
请注意,此代码还计算孔内所需的边界。但我们不需要将其包含在我们的答案中。但是,我不知道如何从我们的答案中排除这一点......
为什么我提到青铜问题
如果你看到青铜问题的解决方案(这只是同一个问题,但有不同的约束(,Brian Dean先生也在这里实现了这种递归解决方案,类似于我在代码中所做的。代码如下:
#include <stdio.h>
#define MAX_N 100
int already_visited[MAX_N+2][MAX_N+2];
int occupied[MAX_N+2][MAX_N+2];
int perimeter;
int valid(int x, int y)
{
return x>=0 && x<=MAX_N+1 && y>=0 && y<=MAX_N+1;
}
void visit(int x, int y)
{
if (occupied[x][y]) { perimeter++; return; }
if (already_visited[x][y]) return;
already_visited[x][y] = 1;
if (valid(x-1,y)) visit(x-1,y);
if (valid(x+1,y)) visit(x+1,y);
if (valid(x,y-1)) visit(x,y-1);
if (valid(x,y+1)) visit(x,y+1);
}
int main(void)
{
int N, i, x, y;
freopen ("perimeter.in", "r", stdin);
freopen ("perimeter.out", "w", stdout);
scanf ("%d", &N);
for (i=0; i<N; i++) {
scanf ("%d %d", &x, &y);
occupied[x][y] = 1;
}
visit(0,0);
printf ("%dn", perimeter);
return 0;
}
为什么此解决方案不适用于白银
这是因为我正在解决的问题的白银版本中的约束具有更高的约束,但时间限制相同。这会使代码超时。
因此,如果有人能帮助我解决这个问题,以排除中间孔所占用的周长,我将不胜感激。
您的解决方案与发布的第二个解决方案非常相似。但是你不是在草捆上行走,而是在外围行走:
void solve(int i, int j){
if(vis[mp(i,j)]) return;
if(exists[mp(i,j)]) return;
if(there_is_no_bale_next_to(i,j)) return; // consider all 8 directions
vis[mp(i,j)] = true;
ans ++;
solve(i-1,j);
solve(i+1,j);
solve(i,j+1);
solve(i,j-1);
}
您首先在绝对在周边的点(如最西端(上运行solve
。
您的解决方案的问题在于它以"X"点为目标,这也不可避免地会计算孔数。请考虑启动一个在物体周围移动而不实际进入物体的洪水填充。我下面的解决方案实现了这个想法,因此不计算漏洞。布莱恩·迪恩(Brian Dean(在官方社论中的解决方案也是基于这个想法,所以你也应该看看。
#include<bits/stdc++.h>
using namespace std;
int n, ans = 0;
map<pair<int,int>, bool> m, vis;
pair<int,int> p = {INT_MAX, INT_MAX};
bool adj (int i, int j) {
for (int x = -1; x <= 1; x++) {
for (int y = -1; y <= 1; y++) {
if (!x & !y) continue;
if (m[{i + x, j + y}]) return true;
}
}
return false;
}
int get_cnt (int i, int j) {
int res = 0;
if (m[{i, j + 1}]) res++;
if (m[{i, j - 1}]) res++;
if (m[{i + 1, j}]) res++;
if (m[{i - 1, j}]) res++;
return res;
}
void floodfill (int i, int j) {
if (m[{i, j}] || vis[{i, j}] || !adj(i, j)) return;
vis[{i, j}] = true;
ans += get_cnt(i, j);
floodfill (i, j + 1);
floodfill (i, j - 1);
floodfill (i + 1, j);
floodfill (i - 1, j);
}
int main () {
cin >> n;
for (int i = 0; i < n; i++) {
int x, y;
cin >> x >> y;
m[{x, y}] = true;
p = min(p, {x, y});
}
floodfill (p.first - 1, p.second);
cout << ans << endl;
}
- 运行同一解决方案的另一个项目的项目
- Project Euler问题4的错误解决方案
- Ardunio UNO解决了多个重叠的定时器循环
- 如何解决gcc编译器优化导致的centos双编译器设置中的分段错误
- 两个文件使用彼此的功能-如何解决
- 计算每个节点的树高,帮助我解释这个代码解决方案
- 如何解决"invalid conversion from 'char' to 'const char*'"
- 在java中解决这段代码时面临循环中的问题
- C++:Application.cpp中抛出了未解析的外部符号(解决方案在问题的末尾,供未来的读者参考)
- 难以理解某些人解决IOI问题的源代码
- visual c++,如何获取解决方案目录中的代码
- 如何解决错误:SCIP C++中的 SCIP 阶段无效 <10>
- 节俭并发:未解决的外部问题
- IpOpt拒绝解决不受约束的问题
- Usaco第1.6节主要回文
- 如何解决这个超硬恒星的创造问题
- 循环无限运行C++解决骑士之旅问题
- 如何递归地解决USACO 2013-周长-银
- 解决 USACO 1.1 – 十三号星期五与日期.h.
- 为什么USACO分级师不接受我的"Prime Cryptarithm"解决方案?(我的电脑和在线评分机之间的输出差异)