Codeforces Round #355 (Div. 2) D. Vanya and Treasure dp+分块
題目鏈接:
http://codeforces.com/contest/677/problem/D
題意:
讓你求最短的從start->...->1->...->2->...->3->...->...->p的最短路徑。
題解:
這題dp的階段性還是很明顯的,相同的值得方格為同一個(gè)階段,然后求從階段1->2->3...->p的階段圖最短路。
初始化所有a[x][y]==1的格子為起始點(diǎn)到(x,y)坐標(biāo)的距離。
方程式為dp[x1][y1]=min(dp[x1][y1],dp[x2][y2]+abs(x2-x1)+abs(y2-y1)),其中a[x1][y1]=a[x2][y2]+1。
但是這要n*n*m*m的復(fù)雜度。
x階段到x+1階段的轉(zhuǎn)移數(shù)為cnt[x]*cnt[x+1],這個(gè)太大,并且多來(lái)幾個(gè)就會(huì)爆了,但注意如果cnt[x]*cnt[x+1]大了,其他的如
cnt[x']*cnt[x'+1]就有可能會(huì)變小,因?yàn)閟um(cnt[i])是固定的,
那么根據(jù)這個(gè)特性,我們可以考慮分塊!,當(dāng)cnt[x]*cnt[x+1]<=m*n的時(shí)候直接暴力,如果大了就用最短路(spfa就可以)
這樣跑出來(lái)的時(shí)間復(fù)雜度為O(n*m*sqrt(n*m)*log(n*m)),那個(gè)log(n*m)是spfa跑出來(lái)的。
具體的均攤時(shí)間復(fù)雜度證明:http://codeforces.com/blog/entry/45181?#comment-297475
代碼:
#include<iostream> #include<cstdio> #include<cstring> #include<utility> #include<vector> #include<algorithm> #include<queue> #define mp make_pair #define X first #define Y second using namespace std;const int maxn = 305;int dp[maxn][maxn],mat[maxn][maxn]; int cnt[maxn*maxn],inq[maxn][maxn],d[maxn][maxn]; vector<pair<int,int> > G[maxn*maxn]; int n, m, p;inline int get_dis(int x1, int y1, int x2, int y2) {return abs(x1 - x2) + abs(y1 - y2); }const int dx[] = { -1,1,0,0 }; const int dy[] = { 0,0,-1,1 };void init() {memset(dp, 0x7f, sizeof(dp));memset(cnt, 0, sizeof(cnt)); }int main() {while (scanf("%d%d%d", &n, &m, &p) == 3 && n) {init();int xt, yt;for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {scanf("%d", &mat[i][j]);if (mat[i][j] == 1) dp[i][j] = get_dis(0,0,i,j);if (mat[i][j] == p) xt = i, yt = j;cnt[mat[i][j]]++;G[mat[i][j]].push_back(mp(i, j));}}for (int i = 2; i <= p; i++) {if (cnt[i - 1] * cnt[i] <= m*n) {for (int j = 0; j < G[i].size(); j++) {int x2 = G[i][j].X, y2 = G[i][j].Y;for (int k = 0; k < G[i - 1].size(); k++) {int x1 = G[i - 1][k].X, y1 = G[i - 1][k].Y;dp[x2][y2] = min(dp[x2][y2], dp[x1][y1] + get_dis(x1, y1, x2, y2));}}}else {memset(d, 0x7f, sizeof(d));memset(inq, 0, sizeof(inq));queue<pair<int, int> > Q;for (int j = 0; j < G[i - 1].size(); j++) {pair<int, int> u = G[i - 1][j];d[u.X][u.Y] = dp[u.X][u.Y], inq[u.X][u.Y] = 1;Q.push(mp(u.X, u.Y));}while (!Q.empty()) {pair<int, int> u = Q.front(); Q.pop();inq[u.X][u.Y] = 0;if (mat[u.X][u.Y] == i) dp[u.X][u.Y] = min(dp[u.X][u.Y], d[u.X][u.Y]);for (int j = 0; j < 4; j++) {int x = u.X + dx[j], y = u.Y + dy[j];if (x < 0 || x >= n || y < 0 || y >= m) continue;if (d[x][y] > d[u.X][u.Y] + 1) {d[x][y] = d[u.X][u.Y] + 1;if (!inq[x][y]) inq[x][y] = 1, Q.push(mp(x, y));}}}}}printf("%d\n", dp[xt][yt]);}return 0; }?
轉(zhuǎn)載于:https://www.cnblogs.com/fenice/p/5554956.html
總結(jié)
以上是生活随笔為你收集整理的Codeforces Round #355 (Div. 2) D. Vanya and Treasure dp+分块的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 个人工作总结10(第二阶段)
- 下一篇: golang 编写的邮件客户端