感覺還是比動規簡單一些的……但是最近腦子有點糊。
首先是要注意鄰接表是有兩種的,在稀疏圖中,最好用vector存每個頂點的邊的資訊,而不是稠密圖中的g[x][y]。
第二是步數最少的路徑……存path然後把path拷貝到bestpath……要不然會亂。我犯了很多次傻然後後面debug。這個錯誤很蠢但是我一開始也沒想清楚。
下面是一些具體問題。
百練2815 城堡問題
基本上可以算乙個連通圖的模板題了。但是有幾個點。首先是如何統計房間的數量?我反正是沒想到,把不同的房間用不同的數字染色。統計顏色的數量就好了。然後就是把visited返回要放在dfs外面……要不然邏輯上有問題,我也是蠢了。
最後ac**:
//百練2815:城堡問題
#include #include using namespace std;
const int maxm = 51;
int dx = ;
int dy = ;
int visited[maxm][maxm];
int m, n;
int map[maxm][maxm];
int legal(int x, int y)
int roomnum;
int maxroomsize;
int cursize;
int dfs(int x, int y)
return 1;
}int main()
} int init = 1;
for (int i = 0; i < m; ++i)
} cout << roomnum << endl;
cout << maxroomsize << endl;
return 0;
}
或者下面這種:
//百練2815:城堡問題
#include #include using namespace std;
const int maxm = 51;
int dx = ;
int dy = ;
int visited[maxm][maxm];
int m, n;
int map[maxm][maxm];
int legal(int x, int y)
int roomnum;
int maxroomsize;
int cursize;
int dfs(int x, int y, int & cursize)
maxroomsize = max(maxroomsize, cursize);
return 1;
}int main()
} int init = 1;
for (int i = 0; i < m; ++i)
} cout << roomnum << endl;
cout << maxroomsize << endl;
return 0;
}
百練1724 roads
我其實看了課件才有思路的……好吧。就是要把cost拿出來作為一維度存中間結果。
這個題就是注意道路不止一條,所以要用vector存,不能用鄰接矩陣。
另外值得一提的是有乙個剪枝會導致wa。就是如果下乙個目的地不是n而道路的花費加上已經有的花費等於k的時候剪枝。這個是錯的因為有可能某條路花銷為0.
還有就是我嘗試用動規做,也就是「我為人人」,狀態轉移方程為:
minlength[roadinfo[i][j].dest][cost] = min(minlength[roadinfo[i][j].dest][cost], minlength[i][k] + roadinfo[i][j].length)
但是實際上是不行的。因為要考慮到回頭路的存在,因此搜尋順序就成了個問題,因為現在就不能從i=1搜到i=n了。
最後ac**:
#include #include #include #include using namespace std;
const int maxn = 102;
const int maxk = 10002;
const int maxr = 10002;
const int inf = (1 << 30);
int n, k, r;
struct road;
vector roadinfo[maxn][maxn];
//int roadinfo[maxn][maxn][2];
int minlength[maxn][maxk];
int output = inf;
int visited[maxn];
int dfs(int location, int cost, int curlength)
} for (int i = 2; i <= n; ++i)
} }return 0;
}int main()
for (int i = 0; i < maxn; ++i)
} minlength[1][0] = 0;
visited[1] = 1;
dfs(1, 0, 0);
cout << (output == inf? -1: output) << endl;
return 0;
}
其實寫得有點囉嗦……
百練1190 生日蛋糕
這個是例題,主要的啟示是可行性剪枝的預見性。還有搜尋順序從大到小,從下往上,便於可行性剪枝(這讓我想起聚類和動規……自底向上好像都比自頂向下要效率高?應該這樣可以排掉大量的可能性)。另外這個題目有很多細節上的處理要注意的。
首先是蛋糕的表面積,包括所有層的頂部露在外面的面積和側面積,而前一部分直接就等於最底層的底面積。而且注意不要忘了加。
另外是從底層最大高度和半徑開始列舉,設定的是int,注意這個是捨去小數部分的,因此要+1再開始列舉。
最後是還有乙個可以改進的地方是記憶化搜尋。
最後的ac**(抄講義的(捂臉)):
#include #include #include const int maxn = 10000, maxm = 20;
int n, m;
int minv[maxm+1];
int mina[maxm+1];
int maxv[maxm+1][30][30];
int minarea = 0xffffff;
int area;
int calmaxv(int curdepth, int r, int h)
maxv[curdepth][r][h] = v;
return v; }}
int dfs(int curdepth, int remv, int maxr, int maxh)
else return 0;
} if (minv[curdepth-1] > remv) return 0;
if (mina[curdepth-1] + area >= minarea) return 0;
if (calmaxv(curdepth, maxr, maxh) < remv) return 2;
//printf("escape return\n");
for (int r = maxr; r >= curdepth; --r)
else area -= 2 * r * h;
} }return 0;
}int main()
if (minv[m] > n) printf("0\n");
else
return 0;
}
海賊王之偉大航路
這個其實是生日蛋糕的變式題。那個可行性剪枝(就那個蛋糕裡面最強的剪枝)我沒想到,一開始想的乙個作死的o(n^2)版本,試了好幾次才幡然醒悟自己的愚蠢……這其實有點像啟發式函式。最後我採取的策略是記錄所有 的道路cost裡面最小的那個,然後如果已經有的pathcost加上(n-depth)*mincost比最優解大就捨掉,事實證明儘管這個啟發式函式相比蛋糕裡面的相當之不靠譜,但是還是非常有用的。
最後ac**:
#include #include #include using namespace std;
int minpath = 0xffffff;
bitset<16> vstd;
int n;
int minr = 0xffffff;
int route[16][16];
int dfs(int location, int path, int depth)
vstd[location] = 1;
if (path >= minpath)
for (int i = 1; i < n; ++i)
vstd[location] = 0;
return 0;
}int main()
} dfs(0, 0, 0);
printf("%d\n", minpath);
return 0;
}
(本來一開始還想嘗試a搜尋然後失敗了,事實證明根本不懂a演算法(捂臉),考完有空研究一下)
先這些吧。
深度優先搜尋經典題目
michael喜歡滑雪百這並不奇怪,因為滑雪的確很刺激。可是為了獲得速度,滑的區域必須向下傾斜,而且當你滑到坡底,你不得不再次走上坡或者等待公升降機來載你。michael想知道載乙個區域中最長的滑坡。區域由乙個二維陣列給出。陣列的每個數字代表點的高度。下面是乙個例子 1 2 3 4 5 16 17 ...
廣度優先搜尋 深度優先搜尋
前言 這幾天複習圖論演算法,覺得bfs和dfs挺重要的,而且應用比較多,故記錄一下。廣度優先搜尋 有乙個有向圖如圖a 圖a廣度優先搜尋的策略是 從起始點開始遍歷其鄰接的節點,由此向外不斷擴散。1.假設我們以頂點0為原點進行搜尋,首先確定鄰接0的頂點集合s0 2.然後確定頂點1的集合s1 頂點2沒有鄰...
廣度優先搜尋,深度優先搜尋
深度優先搜尋 depth first search 簡稱dfs。最直觀的例子就是 走迷宮 廣度優先搜尋 每個頂點都要進出一遍佇列,每個邊也都會被訪問一次,所以 時間複雜度o v e 主要消耗記憶體的是visited prev陣列 queue佇列,所以 空間複雜度o v 深度優先搜尋 每條邊最多會被訪...