国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

OJ 7223 至少有多少只惱人的大青蛙?__深搜

2019-11-08 02:15:34
字體:
來源:轉載
供稿:網友

描述

有一種大青蛙會跳越稻田,從而踩踏稻子。農民在早上看到被踩踏的稻子,希望知道晚上有多少青蛙穿越自家的稻田。每只青蛙總是沿著一條直線跳躍稻田,而且每次跳躍的距離都相同。 這里寫圖片描述

如圖1和圖2所示,稻田里的稻子組成一個柵格,每棵稻子位于一個格點上。而青蛙總是從稻田的一側跳進稻田,然后沿著某條直線穿越稻田,從另一側跳出去。 這里寫圖片描述

如圖3所示,可能會有多只青蛙從稻田穿越。青蛙的每一跳都恰好踩在一棵水稻上,將這棵水稻踩壞。有些水稻可能被多只青蛙踩踏。當然,農民所見到的是圖4中的情形,并看不到圖3中的直線,也見不到別人家田里被踩踏的水稻。需要注意的是,農民可以根據水稻踩壞的程度來精確計算出一共幾只青蛙踩踏過這一棵水稻,所以聰明的農民就能得到圖4的水稻毀壞程度圖。 這里寫圖片描述

我們可以認為每條青蛙跳躍路徑上至少包括3棵被踩踏的水稻。而在一條青蛙跳躍路徑的直線上,也可能會有些被踩踏的水稻不屬于該行走路徑,例如青蛙跳躍路徑(2,3)(4,5)(6,7)經過(3,4),而(3,4)不屬于跳躍路徑。

注意:同一只青蛙不會第二次跳入同一片稻田,可能存在不同的兩只青蛙的跳躍路徑完全一樣。

現在給定水稻破壞程度圖,請你寫一個程序,確定:最少有多少只青蛙穿越了稻田。例如,圖4的答案是4,圖3所示的跳躍路徑數量就是答案。輸入數據保證有解且最多14只青蛙穿越稻田。

輸入

從標準輸入設備上讀入數據。第一行為測試數據數目。每組測試數據第一行上兩個整數R、C,分別表示稻田中水稻的行數和列數,1≤R、C≤50。第二行是一個整數N,表示被踩踏的水稻數量, 3≤N≤700。在剩下的N行中,每行有三個整數,分別是一顆被踩踏水稻的行號(1~R)、列號(1~C)和被踩踏次數,三個整數之間用空格隔開。每棵被踩踏水稻只被列出

輸出

對于每一組測試數據從標準輸出設備上輸出一個整數,表示最少有幾只青蛙穿越了稻田。

樣例輸入

1 6 7 14 2 1 1 2 2 1 2 3 2 2 4 1 2 5 1 2 6 2 2 7 1 3 4 1 4 2 1 4 5 1 6 1 1 6 3 1 6 5 1 6 7 2

樣例輸出

4

分析

最開始看的題就是惱人的青蛙,最后一道題沒想到會又與這個話題有關。枚舉前兩個點,之后再遞歸看能否讓所有的點歸于有效路徑里面,按原來的思路改寫后TLE,之后又加了些剪枝方式,示例降到1ms,但OJ上測試還是TLE,嘗試多次無果,先放著吧,有空再想想,如果有了解怎么有效剪枝麻煩回復下這里寫圖片描述

實現

#include <iostream>#include <algorithm>#include <vector>#include <ctime>#include <map>#define KEY(plant) ((plant.x << 6) + plant.y)using namespace std;int r, c, n, totalPlantCount, minPathCount;struct PLANT{ int x, y, num;};PLANT plants[701];PLANT plant;map<int, int> pointMap;vector<int> searchPath(int i, int j, PLANT secPlant, int dX, int dY);void findNextPathStartPlant(int startX, int plantCount, int pathCount) { //如果所有踐踏點都已覆蓋掉的話則更新最小路徑數,即最小青蛙數。 if (plantCount == 0) { minPathCount = minPathCount > pathCount ? pathCount : minPathCount; return; } if (pathCount >= minPathCount) { return; } int dX, dY, pX, pY, findFirstJ; for (int i = startX; i < n - 2; i++) { if (plants[i].num <= 0) continue;//plants[i]是第一個點,必須保證未用完踩踏點。 findFirstJ = 0; for (int j = i + 1; j < n - 1; j++) { if (plants[j].num <= 0) continue;//plants[j]是第二個點,必須保證未用完踩踏點。 if (plants[i].num <= 0) break; if (!findFirstJ) { findFirstJ = j; } dX = plants[j].x - plants[i].x; dY = plants[j].y - plants[i].y; pX = plants[i].x - dX; pY = plants[i].y - dY; //第一點的前一點在稻田里, 說明本次選的第二點導致的x方向步長不合理(太小) //取下一個點作為第二點 if (pX <= r && pX >= 1 && pY <= c && pY >= 1) continue; //x方向過早越界了. 說明本次選的第二點不成立 //如果換下一個點作為第二點, x方向步長只會更大, 更不成立, 所以應該 //認為本次選的第一點必然是不成立的, 那么取下一個點作為第一點再試 pX = plants[j].x + dX; if (pX > r || pX < 1) break; pY = plants[j].y + dY; if (pY > c || pY < 1) continue; //y方向過早越界了, 應換一個點作為第二點再試 vector<int> plantPos = searchPath(i, j, plants[j], dX, dY); if (plantPos.size() > 0) { plantCount -= plantPos.size(); //是一條路徑則將所有踩踏點的可踩踏數減1。 for (std::vector<int>::const_iterator iter = plantPos.cbegin(); iter != plantPos.cend(); ++iter) {// PLANT currPlant = plants[(*iter)]; // cout << "(" << currPlant.x << ", " << currPlant.y << ", " << currPlant.num << ") "; plants[(*iter)].num--; } findNextPathStartPlant(i + 1, plantCount, pathCount + 1); //恢復 plantCount += plantPos.size(); for (std::vector<int>::const_iterator iter = plantPos.cbegin(); iter != plantPos.cend(); ++iter) { plants[(*iter)].num++; } } } if (plants[i].num > 0) { //當前點沒消耗完說明是孤立點,永遠不可能踩到。 return; } if (findFirstJ) { i = findFirstJ; } //直到跳到下一個可用的點。 }}int main() {// freopen("in.txt", "r", stdin);// const clock_t begin_time = std::clock(); int t; scanf("%d", &t); while (t--) { totalPlantCount = 0; minPathCount = 15; pointMap.clear(); scanf("%d %d", &r, &c); //行數和列數, x方向是上下, y方向是左右 scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%d %d %d", &plants[i].x, &plants[i].y, &plants[i].num); pointMap[KEY(plants[i])] = i; totalPlantCount += plants[i].num; } //將水稻按x坐標從小到大排序, x坐標相同按y從小到大排序 sort(plants, plants + n); findNextPathStartPlant(0, totalPlantCount, 0); Operator <(const PLANT& p1, const PLANT& p2) { if (p1.x == p2.x) return p1.y < p2.y; return p1.x < p2.x;}bool operator ==(const PLANT& p1, const PLANT& p2) { return p1.x == p2.x && p1.y == p2.y;}int binarySearch(PLANT* a, int start, int end, PLANT key) { int l = start, r = end - 1; while (l <= r) { int mid = l + (r - l) / 2; if (a[mid] == key) return mid; else if (a[mid] < key) l = mid + 1; else r = mid - 1; } return -1;}//判斷從 secPlant點開始, 步長為dx, dy, 那么最多能走幾步vector<int> searchPath(int i, int j, PLANT secPlant, int dX, int dY) { vector<int> plantPos; plantPos.push_back(i); plantPos.push_back(j); PLANT plant; plant.x = secPlant.x + dX; plant.y = secPlant.y + dY;// int pos = j, end; while (plant.x <= r && plant.x >= 1 && plant.y <= c && plant.y >= 1) {// end = pos + r * dX + dY + 1;// if (end >= n) {// end = n;// }// pos = binarySearch(plants, pos, end, plant); int key = KEY(plant); if (pointMap.count(key) > 0 && plants[pointMap[key]].num > 0) { plantPos.push_back(pointMap[key]); plant.x += dX; plant.y += dY; } else { //not found, 每一步都必須踩倒水稻才算合理, 否則這就不是一條行走路徑 plantPos.clear(); break; } } return plantPos;}
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 巩留县| 如东县| 巴南区| 普定县| 昭苏县| 治县。| 斗六市| 英吉沙县| 嘉兴市| 延长县| 司法| 达日县| 崇州市| 清河县| 宝山区| 常州市| 宣汉县| 临高县| 平湖市| 临颍县| 松原市| 永顺县| 张家川| 赤壁市| 尼木县| 河北省| 长兴县| 霍林郭勒市| 嘉禾县| 景宁| 尖扎县| 湘潭市| 塔城市| 新建县| 吴桥县| 望谟县| 眉山市| 邹城市| 西乌| 中阳县| 博湖县|