7.6 แบบฝึกหัด
เขียนแต่ละข้อเป็นไฟล์ใหม่ใน Code::Blocks รันแล้วเทียบกับผลลัพธ์ที่ต้องได้ให้ตรงทุกตัวอักษร รวมถึงช่องว่างและการขึ้นบรรทัด ติดจริงๆ ค่อยเปิดคำใบ้ และเปิดเฉลยหลังทำเสร็จแล้วเท่านั้น
ข้อ 1 ยอดขายร้านน้ำปั่น
ร้านน้ำปั่นหน้าโรงเรียนจดยอดขายไว้ N วัน แต่ละวันจดว่าเมนูแต่ละเมนูจากทั้งหมด M เมนูขายได้กี่แก้ว ตัวเลขในแถวที่ i คอลัมน์ที่ j คือจำนวนแก้วของเมนูที่ j ที่ขายได้ในวันที่ i เจ้าของร้านอยากรู้ว่าวันไหนขายรวมได้มากที่สุด และเมนูไหนขายรวมทุกวันได้มากที่สุด ถ้ามีหลายวันหรือหลายเมนูที่ยอดรวมเท่ากัน ให้ตอบหมายเลขที่น้อยที่สุด วันและเมนูมีหมายเลขเริ่มจาก 1
ข้อมูลเข้า
บรรทัดแรกมีจำนวนเต็ม N และ M (1 ≤ N, M ≤ 100) อีก N บรรทัดต่อมา บรรทัดละ M จำนวน คือจำนวนแก้วที่ขายได้ แต่ละจำนวนอยู่ระหว่าง 0 ถึง 1000
ข้อมูลออก
บรรทัดแรกพิมพ์หมายเลขวันที่ขายรวมได้มากที่สุด ตามด้วยยอดรวมของวันนั้น บรรทัดที่สองพิมพ์หมายเลขเมนูที่ขายรวมได้มากที่สุด ตามด้วยยอดรวมของเมนูนั้น คั่นด้วยช่องว่าง
3 4
12 5 8 3
7 15 10 9
9 11 6 142 41
2 31ดูคำใบ้
ยอดรวมของแต่ละวันคือผลรวมตามแถว ยอดรวมของแต่ละเมนูคือผลรวมตามคอลัมน์ แบบในหน้า 7.2 ระหว่างที่รวมได้ทีละตัว ให้เทียบกับค่ามากสุดที่เจอมาแล้วไปเลย ใช้ > ไม่ใช่ >= ถ้าเสมอกันจะได้หมายเลขที่น้อยกว่า และลองคิดว่าถ้าทุกช่องเป็น 0 โปรแกรมของน้องจะตอบวันที่เท่าไร
ดูเฉลย
#include <stdio.h>
int sales[100][100];
int main()
{
int days, menus;
scanf("%d %d", &days, &menus);
for (int r = 0; r < days; r++) {
for (int c = 0; c < menus; c++) {
scanf("%d", &sales[r][c]);
}
}
int best_day = 0, best_day_total = -1;
for (int r = 0; r < days; r++) {
int total = 0;
for (int c = 0; c < menus; c++) {
total += sales[r][c];
}
if (total > best_day_total) {
best_day = r;
best_day_total = total;
}
}
int best_menu = 0, best_menu_total = -1;
for (int c = 0; c < menus; c++) {
int total = 0;
for (int r = 0; r < days; r++) {
total += sales[r][c];
}
if (total > best_menu_total) {
best_menu = c;
best_menu_total = total;
}
}
printf("%d %d\n", best_day + 1, best_day_total);
printf("%d %d\n", best_menu + 1, best_menu_total);
return 0;
}ข้อ 2 ผลรวมใต้ตัว X
ครูให้ตารางตัวเลขขนาด N × N มา แล้วให้นักเรียนลากเส้นทแยงสองเส้นเป็นรูปตัว X เส้นแรกจากมุมบนซ้ายไปมุมล่างขวา เส้นที่สองจากมุมบนขวาไปมุมล่างซ้าย ให้หาผลรวมของตัวเลขที่เส้นแรกลากผ่าน ผลรวมของตัวเลขที่เส้นที่สองลากผ่าน และผลรวมของตัวเลขทุกตัวที่ถูกตัว X ทับ ตัวเลขที่ถูกทั้งสองเส้นทับให้นับครั้งเดียว
ข้อมูลเข้า
บรรทัดแรกมีจำนวนเต็ม N (1 ≤ N ≤ 100) อีก N บรรทัดต่อมา บรรทัดละ N จำนวน แต่ละจำนวนอยู่ระหว่าง -1000000000 ถึง 1000000000
ข้อมูลออก
สามบรรทัด บรรทัดแรกคือผลรวมบนเส้นจากมุมบนซ้าย บรรทัดที่สองคือผลรวมบนเส้นจากมุมบนขวา บรรทัดที่สามคือผลรวมของตัวเลขทุกตัวที่ถูกตัว X ทับ
3
4 9 2
3 5 7
8 1 615
15
254
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 1634
34
68ดูคำใบ้
เส้นทแยงหลักคือ a[i][i] เส้นทแยงรองคือ a[i][N - 1 - i] ตามหน้า 7.2 บรรทัดที่สามคือผลรวมของสองเส้นบวกกัน แต่ถ้า N เป็นเลขคี่ ช่องกลางถูกนับไปสองครั้ง ต้องลบออกหนึ่งครั้ง ลองกับ N = 1 ด้วย และดูขอบเขตของตัวเลขให้ดี ผลรวม 100 ตัวที่แต่ละตัวถึง 109 ใส่ int ไม่พอ
ดูเฉลย
#include <stdio.h>
int a[100][100];
int main()
{
int n;
scanf("%d", &n);
for (int r = 0; r < n; r++) {
for (int c = 0; c < n; c++) {
scanf("%d", &a[r][c]);
}
}
long long main_sum = 0, anti_sum = 0;
for (int i = 0; i < n; i++) {
main_sum += a[i][i];
anti_sum += a[i][n - 1 - i];
}
long long cross = main_sum + anti_sum;
if (n % 2 == 1) {
cross -= a[n / 2][n / 2];
}
printf("%lld\n%lld\n%lld\n", main_sum, anti_sum, cross);
return 0;
}ข้อ 3 หมุนรูปภาพ
กล้องของชมรมถ่ายภาพบันทึกรูปขาวดำเป็นตารางตัวอักษร R แถว C คอลัมน์ # คือจุดสีดำ . คือจุดสีขาว แต่น้องถือกล้องตะแคงตอนถ่าย รูปจึงออกมานอนอยู่ ให้หมุนรูปไปทางขวา 90 องศา ตามเข็มนาฬิกา มุมบนซ้ายของรูปเดิมจะไปอยู่มุมบนขวาของรูปใหม่
ข้อมูลเข้า
บรรทัดแรกมีจำนวนเต็ม R และ C (1 ≤ R, C ≤ 100) อีก R บรรทัดต่อมา บรรทัดละ C ตัวอักษรติดกัน แต่ละตัวเป็น # หรือ .
ข้อมูลออก
รูปที่หมุนแล้ว C บรรทัด บรรทัดละ R ตัวอักษรติดกัน
3 5
#....
#....
########
#..
#..
#..
#..ดูคำใบ้
รูปใหม่มี C แถว แถว R คอลัมน์ ลองหมุนรูป 2 × 3 ด้วยมือบนกระดาษ แล้วดูว่าแถวแรกของรูปใหม่มาจากส่วนไหนของรูปเดิม จะเห็นว่ามันคือคอลัมน์แรกของรูปเดิม อ่านจากล่างขึ้นบน ไม่ต้องสร้างตารางใหม่ก็ได้ ใช้ลูปนอกเดินคอลัมน์ ลูปในเดินแถวถอยหลัง แล้วพิมพ์ทีละตัวด้วย %c
ดูเฉลย
#include <stdio.h>
char photo[100][101];
int main()
{
int rows, cols;
scanf("%d %d", &rows, &cols);
for (int r = 0; r < rows; r++) {
scanf("%s", photo[r]);
}
for (int c = 0; c < cols; c++) {
for (int r = rows - 1; r >= 0; r--) {
printf("%c", photo[r][c]);
}
printf("\n");
}
return 0;
}ข้อ 4 เลขบอกทุ่นระเบิด
เกมกู้ระเบิดมีกระดาน R แถว C คอลัมน์ ช่อง * มีทุ่นระเบิด ช่อง . ปลอดภัย ก่อนเริ่มเกม โปรแกรมต้องเติมตัวเลขลงในทุกช่องที่ปลอดภัย ตัวเลขคือจำนวนทุ่นระเบิดในช่องที่ติดกับช่องนั้นทั้ง 8 ทิศ รวมช่องทแยงด้วย ช่องที่มีทุ่นระเบิดให้คงเป็น * ไว้
ข้อมูลเข้า
บรรทัดแรกมีจำนวนเต็ม R และ C (1 ≤ R, C ≤ 100) อีก R บรรทัดต่อมา บรรทัดละ C ตัวอักษรติดกัน แต่ละตัวเป็น * หรือ .
ข้อมูลออก
กระดานที่เติมตัวเลขแล้ว R บรรทัด บรรทัดละ C ตัวอักษรติดกัน
4 4
*...
..*.
.*..
...**211
23*1
1*32
112*ดูคำใบ้
ใช้ dr dc แบบ 8 ทิศในหน้า 7.4 นับ * รอบแต่ละช่อง และเช็กขอบก่อนแตะช่องข้างเคียงทุกครั้ง ช่องที่ปลอดภัยพิมพ์จำนวนด้วย %d ช่องที่มีทุ่นระเบิดพิมพ์ * ทุกตัวในแถวพิมพ์ติดกันโดยไม่เว้นวรรค แล้วขึ้นบรรทัดใหม่เมื่อจบแถว
ดูเฉลย
#include <stdio.h>
char board[100][101];
int dr[8] = {-1, -1, -1, 0, 0, 1, 1, 1};
int dc[8] = {-1, 0, 1, -1, 1, -1, 0, 1};
int main()
{
int rows, cols;
scanf("%d %d", &rows, &cols);
for (int r = 0; r < rows; r++) {
scanf("%s", board[r]);
}
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
if (board[r][c] == '*') {
printf("*");
} else {
int mines = 0;
for (int d = 0; d < 8; d++) {
int nr = r + dr[d];
int nc = c + dc[d];
if (nr >= 0 && nr < rows && nc >= 0 && nc < cols && board[nr][nc] == '*') {
mines++;
}
}
printf("%d", mines);
}
}
printf("\n");
}
return 0;
}ข้อ 5 ความยาวชายฝั่ง
แผนที่หมู่เกาะเป็นตาราง R แถว C คอลัมน์ ช่อง # คือบก ช่อง . คือน้ำ และทุกที่นอกแผนที่ก็เป็นน้ำ แต่ละช่องเป็นสี่เหลี่ยมจัตุรัสด้านยาว 1 กิโลเมตร ชายฝั่งคือด้านของช่องบกที่ติดกับน้ำ รวมถึงทะเลสาบที่อยู่กลางเกาะด้วย ให้หาความยาวชายฝั่งทั้งหมดเป็นกิโลเมตร
ข้อมูลเข้า
บรรทัดแรกมีจำนวนเต็ม R และ C (1 ≤ R, C ≤ 100) อีก R บรรทัดต่อมา บรรทัดละ C ตัวอักษรติดกัน แต่ละตัวเป็น # หรือ .
ข้อมูลออก
ความยาวชายฝั่งทั้งหมดเป็นกิโลเมตร
5 6
......
.##...
.###..
...#..
......123 5
#####
#...#
#####24ดูคำใบ้
มองทีละช่องที่เป็น # แล้วดูทั้ง 4 ด้านด้วย dr dc ด้านไหนออกนอกแผนที่ หรือติดกับ . ด้านนั้นคือชายฝั่งหนึ่งหน่วย ด้านที่ติดกับ # อีกช่องอยู่บนบก ไม่นับ ข้อนี้ช่องที่ออกนอกแผนที่ต้องนับ ไม่ใช่ข้าม ลองกับแผนที่ที่เป็นบกทั้งหมดดู ต้องได้ 2 × (R + C)
ดูเฉลย
#include <stdio.h>
char map[100][101];
int dr[4] = {-1, 1, 0, 0};
int dc[4] = {0, 0, -1, 1};
int main()
{
int rows, cols;
scanf("%d %d", &rows, &cols);
for (int r = 0; r < rows; r++) {
scanf("%s", map[r]);
}
int coast = 0;
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
if (map[r][c] == '#') {
for (int d = 0; d < 4; d++) {
int nr = r + dr[d];
int nc = c + dc[d];
if (nr < 0 || nr >= rows || nc < 0 || nc >= cols || map[nr][nc] == '.') {
coast++;
}
}
}
}
}
printf("%d\n", coast);
return 0;
}ข้อ 6 คูณเมทริกซ์
ให้เมทริกซ์ A ขนาด N × M และเมทริกซ์ B ขนาด M × P ให้หาผลคูณ A × B ซึ่งเป็นเมทริกซ์ขนาด N × P ช่องแถว i คอลัมน์ j ของผลคูณคือผลรวมของ A[i][k] × B[k][j] ทุกค่า k ตั้งแต่ 1 ถึง M
ข้อมูลเข้า
บรรทัดแรกมีจำนวนเต็ม N M และ P (1 ≤ N, M, P ≤ 100) อีก N บรรทัดต่อมาคือเมทริกซ์ A บรรทัดละ M จำนวน แล้วตามด้วย M บรรทัดของเมทริกซ์ B บรรทัดละ P จำนวน ทุกจำนวนในเมทริกซ์อยู่ระหว่าง -10000 ถึง 10000
ข้อมูลออก
เมทริกซ์ผลคูณ N บรรทัด บรรทัดละ P จำนวน คั่นด้วยช่องว่างหนึ่งช่อง
2 3 2
1 2 0
-1 3 4
2 1
0 -2
5 32 -3
18 5ดูคำใบ้
ใช้ลูปสามชั้นแบบหน้า 7.2 ช่อง [i][j] ของคำตอบคือแถว i ของ A คูณกับคอลัมน์ j ของ B ทีละคู่แล้วบวกกัน อย่าลืมตั้งผลรวมเป็น 0 ก่อนเริ่มแต่ละช่อง ค่าในเมทริกซ์ถึง 104 ผลคูณหนึ่งคู่จึงถึง 108 และบวกกันได้ 100 คู่ ผลรวมถึง 1010 ต้องใช้ long long และ cast ก่อนคูณ
ดูเฉลย
#include <stdio.h>
int a[100][100], b[100][100];
int main()
{
int n, m, p;
scanf("%d %d %d", &n, &m, &p);
for (int i = 0; i < n; i++) {
for (int k = 0; k < m; k++) {
scanf("%d", &a[i][k]);
}
}
for (int k = 0; k < m; k++) {
for (int j = 0; j < p; j++) {
scanf("%d", &b[k][j]);
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < p; j++) {
long long sum = 0;
for (int k = 0; k < m; k++) {
sum += (long long)a[i][k] * b[k][j];
}
printf("%lld", sum);
if (j < p - 1) {
printf(" ");
}
}
printf("\n");
}
return 0;
}ข้อ 7 นับแปลงผัก
สวนผักของโรงเรียนวาดเป็นแผนที่ R แถว C คอลัมน์ ช่อง # ปลูกผัก ช่อง . เป็นทางเดิน ช่อง # ที่ติดกันทางด้านบน ล่าง ซ้าย หรือขวา อยู่ในแปลงเดียวกัน ครูรับรองว่าทุกแปลงเป็นสี่เหลี่ยมผืนผ้าที่ปลูกเต็มทุกช่อง และสองแปลงที่ต่างกันไม่มีด้านติดกันเลย แต่อาจแตะกันที่มุมแบบทแยงได้ ให้นับว่ามีกี่แปลง และแปลงที่ใหญ่ที่สุดมีกี่ช่อง
ข้อมูลเข้า
บรรทัดแรกมีจำนวนเต็ม R และ C (1 ≤ R, C ≤ 100) อีก R บรรทัดต่อมา บรรทัดละ C ตัวอักษรติดกัน แต่ละตัวเป็น # หรือ .
ข้อมูลออก
บรรทัดเดียว มีจำนวนแปลง และจำนวนช่องของแปลงที่ใหญ่ที่สุด คั่นด้วยช่องว่าง ถ้าไม่มีแปลงเลยให้พิมพ์ 0 0
5 6
##..#.
##..#.
......
.###.#
.###..4 64 5
##...
##...
..###
#.###3 6ดูคำใบ้
ทุกแปลงเป็นสี่เหลี่ยมผืนผ้า จึงมีมุมบนซ้ายแค่ช่องเดียว มุมบนซ้ายคือช่อง # ที่ช่องบนไม่ใช่ # และช่องซ้ายก็ไม่ใช่ # (รวมกรณีที่อยู่ขอบแผนที่) นับมุมบนซ้ายก็คือนับแปลง ส่วนขนาดของแปลง ให้เดินจากมุมบนซ้ายไปทางขวาจนหมด # จะได้ความกว้าง แล้วเดินลงล่างจนหมด # จะได้ความสูง
ดูเฉลย
#include <stdio.h>
char garden[100][101];
int main()
{
int rows, cols;
scanf("%d %d", &rows, &cols);
for (int r = 0; r < rows; r++) {
scanf("%s", garden[r]);
}
int plots = 0, largest = 0;
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
int top_free = (r == 0 || garden[r - 1][c] != '#');
int left_free = (c == 0 || garden[r][c - 1] != '#');
if (garden[r][c] == '#' && top_free && left_free) {
plots++;
int width = 0;
while (c + width < cols && garden[r][c + width] == '#') {
width++;
}
int height = 0;
while (r + height < rows && garden[r + height][c] == '#') {
height++;
}
if (width * height > largest) {
largest = width * height;
}
}
}
}
printf("%d %d\n", plots, largest);
return 0;
}ข้อ 8 ไฟป่า
เจ้าหน้าที่อุทยานจำลองไฟป่าบนแผนที่ R แถว C คอลัมน์ ช่อง # คือต้นไม้ ช่อง * คือช่องที่กำลังไหม้ ช่อง . คือพื้นโล่งที่ไม่มีอะไรให้ไหม้ ทุกนาทีทุกช่องเปลี่ยนพร้อมกันตามกฎนี้
- ช่องที่กำลังไหม้
*มอดลงกลายเป็นพื้นโล่ง. - ต้นไม้
#ที่มีช่องติดกันทางด้านบน ล่าง ซ้าย หรือขวา กำลังไหม้อยู่ตอนต้นนาที จะติดไฟกลายเป็น* - ช่องอื่นเหมือนเดิม
ให้หาว่าเมื่อผ่านไป K นาที แผนที่จะเป็นอย่างไร
ข้อมูลเข้า
บรรทัดแรกมีจำนวนเต็ม R C และ K (1 ≤ R, C ≤ 100 และ 1 ≤ K ≤ 100) อีก R บรรทัดต่อมา บรรทัดละ C ตัวอักษรติดกัน แต่ละตัวเป็น # * หรือ .
ข้อมูลออก
แผนที่หลังผ่านไป K นาที R บรรทัด บรรทัดละ C ตัวอักษรติดกัน
4 5 2
#####
##*##
#.###
#.#.##*.*#
*...*
#..*#
#.*.#ดูคำใบ้
ทุกช่องเปลี่ยนพร้อมกัน ต้นไม้จะติดไฟเพราะช่องที่ไหม้อยู่ตอนต้นนาที ไม่ใช่ช่องที่เพิ่งติดไฟในนาทีเดียวกัน ถ้าเขียนผลลงตารางเดิม ไฟจะลามไปหลายช่องในนาทีเดียว เหมือนแบบที่ 2 ในส่วนลองทำให้พังของหน้า 7.4 ให้คิดจากตารางเดิมแล้วเขียนผลลงตารางใหม่ พอคิดครบทุกช่องแล้วค่อยคัดลอกกลับ ทำซ้ำ K รอบ
ดูเฉลย
#include <stdio.h>
char forest[100][101], next_forest[100][101];
int dr[4] = {-1, 1, 0, 0};
int dc[4] = {0, 0, -1, 1};
int main()
{
int rows, cols, minutes;
scanf("%d %d %d", &rows, &cols, &minutes);
for (int r = 0; r < rows; r++) {
scanf("%s", forest[r]);
}
for (int t = 0; t < minutes; t++) {
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
next_forest[r][c] = forest[r][c];
if (forest[r][c] == '*') {
next_forest[r][c] = '.';
} else if (forest[r][c] == '#') {
for (int d = 0; d < 4; d++) {
int nr = r + dr[d];
int nc = c + dc[d];
if (nr >= 0 && nr < rows && nc >= 0 && nc < cols && forest[nr][nc] == '*') {
next_forest[r][c] = '*';
}
}
}
}
}
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
forest[r][c] = next_forest[r][c];
}
}
}
for (int r = 0; r < rows; r++) {
printf("%s\n", forest[r]);
}
return 0;
}ข้อ 9 นับคนในพื้นที่
เทศบาลแบ่งแผนที่เมืองเป็นบล็อก R แถว C คอลัมน์ และรู้ว่าแต่ละบล็อกมีคนอาศัยอยู่กี่คน ทีมวางแผนรถรับส่งนักเรียนมีคำถาม Q ข้อ แต่ละข้อถามว่าในพื้นที่สี่เหลี่ยมที่มีบล็อกแถว r1 คอลัมน์ c1 เป็นมุมบนซ้าย และบล็อกแถว r2 คอลัมน์ c2 เป็นมุมล่างขวา มีคนอาศัยอยู่รวมกี่คน แถวและคอลัมน์เริ่มนับจาก 1
ข้อมูลเข้า
บรรทัดแรกมีจำนวนเต็ม R และ C (1 ≤ R, C ≤ 500) อีก R บรรทัดต่อมา บรรทัดละ C จำนวน คือจำนวนคนในแต่ละบล็อก แต่ละจำนวนอยู่ระหว่าง 0 ถึง 10000 บรรทัดถัดมามีจำนวนเต็ม Q (1 ≤ Q ≤ 50000) อีก Q บรรทัดต่อมา บรรทัดละสี่จำนวน r1 c1 r2 c2 (1 ≤ r1 ≤ r2 ≤ R และ 1 ≤ c1 ≤ c2 ≤ C)
ข้อมูลออก
Q บรรทัด บรรทัดที่ i คือจำนวนคนในพื้นที่ของคำถามที่ i
4 5
4 0 6 2 5
1 8 3 7 0
9 2 5 1 3
0 4 7 6 2
3
2 2 3 4
1 1 4 5
4 1 4 526
75
193 2
3 1
4 1
5 9
3
3 2 3 2
1 1 1 1
2 1 3 29
3
19ดูคำใบ้
บวกทีละช่องทุกคำถามต้องบวกได้ถึง 500 × 500 × 50000 ครั้ง ช้าเกินไป ใช้ตาราง prefix ในหน้า 7.5 เก็บตารางตั้งแต่แถว 1 คอลัมน์ 1 แล้วแต่ละคำถามตอบด้วยการบวกลบสี่ค่า ผลรวมทั้งเมืองถึง 500 × 500 × 10000 = 2.5 × 109 เกิน int ตาราง prefix ต้องเป็น long long
ดูเฉลย
#include <stdio.h>
long long prefix[501][501];
int main()
{
int rows, cols;
scanf("%d %d", &rows, &cols);
for (int r = 1; r <= rows; r++) {
for (int c = 1; c <= cols; c++) {
int people;
scanf("%d", &people);
prefix[r][c] = people + prefix[r - 1][c] + prefix[r][c - 1] - prefix[r - 1][c - 1];
}
}
int questions;
scanf("%d", &questions);
for (int i = 0; i < questions; i++) {
int r1, c1, r2, c2;
scanf("%d %d %d %d", &r1, &c1, &r2, &c2);
printf("%lld\n", prefix[r2][c2] - prefix[r1 - 1][c2] - prefix[r2][c1 - 1] + prefix[r1 - 1][c1 - 1]);
}
return 0;
}ข้อ 10 เก็บทุเรียน
สวนทุเรียนปลูกต้นไม้เป็นตาราง N แถว M คอลัมน์ เจ้าของสวนนับว่าต้นแต่ละต้นมีลูกที่สุกพร้อมเก็บกี่ลูก ได้เลข 0 ถึง 9 วันนี้คนงานเก็บได้แค่พื้นที่สี่เหลี่ยมจัตุรัสขนาด K × K ต้นที่ติดกันหนึ่งพื้นที่ ให้หาว่าควรเลือกพื้นที่ไหนจึงจะได้ทุเรียนสุกมากที่สุด ถ้ามีหลายพื้นที่ที่ได้เท่ากัน ให้เลือกพื้นที่ที่มุมบนซ้ายอยู่แถวบนสุด ถ้ายังเท่ากันอีกให้เลือกพื้นที่ที่มุมบนซ้ายอยู่คอลัมน์ซ้ายสุด แถวและคอลัมน์เริ่มนับจาก 1
ข้อมูลเข้า
บรรทัดแรกมีจำนวนเต็ม N M และ K (1 ≤ N, M ≤ 1000 และ 1 ≤ K ≤ N และ K ≤ M) อีก N บรรทัดต่อมา บรรทัดละ M ตัวอักษรติดกัน แต่ละตัวเป็นเลขโดด 0 ถึง 9 คือจำนวนทุเรียนสุกของต้นนั้น
ข้อมูลออก
บรรทัดแรกพิมพ์จำนวนทุเรียนสุกที่มากที่สุดที่เก็บได้ บรรทัดที่สองพิมพ์แถวและคอลัมน์ของมุมบนซ้ายของพื้นที่ที่เลือก คั่นด้วยช่องว่าง
4 5 2
31415
92653
58979
3238428
3 44 4 2
1001
0000
0110
00002
2 2ดูคำใบ้
มีตำแหน่งให้วางสี่เหลี่ยมได้ (N - K + 1) × (M - K + 1) แบบ ถ้าบวกทีละช่องทุกแบบ เมื่อ N = M = 1000 และ K = 500 ต้องบวกราว 6 × 1010 ครั้ง ไม่ทัน อ่านแต่ละแถวด้วย %s แล้วสร้างตาราง prefix ตามหน้า 7.5 แต่ละตำแหน่งจะหาผลรวมได้ด้วยการบวกลบสี่ค่า ระวังขอบเขตของลูป มุมบนซ้ายของสี่เหลี่ยมไปได้ถึงแถว N - K + 1 และคอลัมน์ M - K + 1 พอดี และถ้าเสมอกันต้องได้ตำแหน่งที่เจอก่อน
ดูเฉลย
#include <stdio.h>
char line[1001][1002];
int prefix[1001][1001];
int main()
{
int rows, cols, k;
scanf("%d %d %d", &rows, &cols, &k);
for (int r = 1; r <= rows; r++) {
scanf("%s", line[r]);
for (int c = 1; c <= cols; c++) {
int ripe = line[r][c - 1] - '0';
prefix[r][c] = ripe + prefix[r - 1][c] + prefix[r][c - 1] - prefix[r - 1][c - 1];
}
}
int best = -1, best_r = 0, best_c = 0;
for (int r = 1; r + k - 1 <= rows; r++) {
for (int c = 1; c + k - 1 <= cols; c++) {
int r2 = r + k - 1, c2 = c + k - 1;
int sum = prefix[r2][c2] - prefix[r - 1][c2] - prefix[r2][c - 1] + prefix[r - 1][c - 1];
if (sum > best) {
best = sum;
best_r = r;
best_c = c;
}
}
}
printf("%d\n%d %d\n", best, best_r, best_c);
return 0;
}