教練上次課講了插頭dp,然後列出的插頭dp題目裡有這道題。本來想練練插頭dp的結果用更快更簡單的斯坦納樹解決了這道題。
斯坦納樹經典題目。
斯坦納樹其實並不是很難,一般用來解決在一張無向圖上選
\(\text\)個點使這\(\text\)個點連通並且始所選邊邊權最小。
那麼回到本題。
設\(f_\)表示當前在第\(\text\)行\(\text\)列的點,狀態為\(\text\)的時候最小權值和。設\(\text\)代表\(\text\)的子集。
那麼轉移方程顯而易見。
\[f_ = min(f_,f_ - a_)
\]這個轉移應該不難看懂吧。
但是這裡會出現乙個問題:那就是會出現新的節點。
我們可以用最短路的方式求出下面乙個方程:
設\(\text\)為當前的節點,\(\text\)是新拓展出的與\(\text\)相連線的節點。
則:\[f_ = min(f_,f_ +a_)
\]然後我們就順利的解決了這道題。
#include const int maxn = 20;
const int maxm = 20;
const int inf = 0x3f3f3f3f;
typedef long long ll;
struct pair
pair(int _x,int _y)
};inline pair make_pair(int x,int y)
templateinline void read(t& res)
const int dir[4][2] = ,,,};
int n, m, i, j, k, tx, ty;
int a[maxn][maxn], f[maxn][maxn][1 << 11];
bool inq[maxn][maxn], ans[maxn][maxn];
struct state
state(int _x,int _y,int _s)
} las[maxn][maxn][1 << 11];
std::queueq;
inline void spfa(int s) }}}
void dfs(int i,int j,int s)
int main()
} for(int l = 1, liml = (1 << cnt) - 1;l <= liml;l++)
}if(f[i][j][l] != inf) q.push(make_pair(i,j)), inq[i][j] = 1;}}
spfa(l);
} printf("%d\n",f[tx][ty][(1 << cnt) - 1]);
dfs(tx,ty,(1 << cnt) - 1);
for(int i = 1;i <= n;i++)
ans[i][j] ? printf("o") : printf("_");
}puts("");
} return 0;
}
P4294 WC2008 遊覽計畫
題目鏈結 題目描述 從未來過紹興的小d有幸參加了winter camp 2008,他被這座歷史名城的秀麗風景所吸引,強烈要求遊覽紹興及其周邊的所有景點。主辦者將紹興劃分為 n nn 行 m mm 列 n m n m n m 個分塊,如下圖 8 景點含於方塊內,且乙個在這裡插入描述 方塊至多有乙個景點...
P4294 WC2008 遊覽計畫 斯坦納樹
題目鏈結 差不多是斯坦納樹裸題,不過邊權化成了點權,這樣在合併兩棵子樹時需要去掉根結點的權值,防止重複。題目還要求輸出解,只要在轉移時記錄下路徑,然後dfs一遍就好了。1 include2 using namespace std 3 typedef long long ll 4 const int ...
洛谷 P1685 遊覽
手玩樣例,我們很快 從題目後的提示 找到了 1 3 1 3 1 3,1 2 31 2 3 1 2 3,1 2 31 2 3 1 2 3 兩者不同 一共三條路徑。求出其權值之和再加上乘船返回兩次所需的時間,和樣例恰好一致。於是我們便可以把這個問題分成兩個子問題逐個求解 選擇從起點開始dfs,我們需要考...