最短路能解決:邊權固定優化
若是邊權和通過點有關,至關因而有後效性,那麼就須要dfsspa
組合:選擇A,B,有一個附加代價C,這種狀況只能搜索3d
缺點就在於枚舉每一種可能性,時間複雜度賊大code
1.狀態表示blog
2.剪枝排序
最優答案(若是某個答案已經比最優答案差了就放棄)隊列
記憶化剪枝(記搜)(還記得數位DP嘛)class
可行性剪枝(字面意思,當前不可行了之後必定也不可行)擴展
能夠看出:搜索
一、n很小
二、圖上沒有重邊,所以邊數𝑚≤28
三、邊與邊之間相互獨立,所以不須要考慮邊與邊之間的相互影響
四、若是圖上出現一棵樹,則已知足連通圖的要求
五、根據提示及第3條,一張圖連通的機率爲:該圖中全部邊都不被淹沒的機率相乘
根據第1條:搜索,考慮每條邊是否加入連通塊
根據第4條:只要連通圖中出現了一棵樹,其他邊是否被淹沒不對答案產生影響
根據第2條:總狀態數爲2^28=268435456,看起來可能會被卡
根據第一、4條:搜索中最多選擇𝑛−1條邊,所以總狀態數小於𝐶_28^7="1184040"。
根據第三、5條:能夠計算出一張圖出現的機率
須要什麼:
一、搜索
二、並查集判斷連通性
簡單的剪枝:
若是剩餘的邊數不夠造成一棵樹,則直接返回
建反圖
原來不能同時存在的x和y有邊,建反圖以後就沒邊了
而後找最大團
先找一個點,往外擴展
對於一個點來講,只有和它有直接邊的點纔有可能與它構成團
就是一個剪枝,每一次通過一個點就把不可能的點都去掉
在一個點以後可能加入的序列中(默認序列點從小到大)
若是當前點的權值加上序列裏全部點的權值都小於當前的答案,就剪枝
從i+1->i,最大答案就是i往前加上i+1
1.刪點—序列
原來序列是123456
先dfs1,和它有邊的點是356,tot=v[1]
而後找3,和它有邊的點是6,tot=v[1]+v[3]
最後是6,沒有和它有邊的點tot=v[1]+v[3]+v[6]
而後把1刪掉,序列變成23456
2.可行點—sum+tot<=ans
3.當前答案—ans[i]+tot<=ans
假如咱們當前到了第i個點,這個點以前的點的ans都已經知道
咱們枚舉j是上一個點,若是ans[j]+tot<ans,那麼j以前的點也不可行(由於ans必定<=j)
ans[i]表示從這個點開始搜的最大的權值和
tot表示當前搜到的最大團的權值和
Ans表示目前的最大的答案
Sum表示序列中剩下的點的權值和
那麼爲了可以當前答案剪枝,咱們就須要把從1到n的序列倒過來dfs,即先算ans[n]
枚舉每一個位置的數,判斷是否能夠放
當前行未出現過
當前列未出現過
當前格子未出現過
更新進入下一層
判斷是否出現可使用二進制
TLE?
倒序枚舉便可
優先擴展淺層節點狀態逐漸深刻
一般用隊列實現
最重要的是判重,即合理的表示狀態
新擴展出的節點若是和之前擴展出的節點相同,則這個新節點就沒必要再考慮
如何平衡時間和空間
狀態(節點)數目巨大,如何存儲?
怎樣才能較快判斷一個狀態是否重複?
先排序(離散化)
Dis[x][y][t]表示在x,y,上一個線索是t的最小步數
queue<pair<int,int> > Q; int FindPath(pair<int,int> b,pair<int,int> e) { for (int i=0;i<n;++i) for (int j=0;j<m;++j) dis[i][j]=1e9+10; Q.push(b); dis[b.first][b.second]=0; while (!Q.empty()) { pair<int,int> u=Q.front(); Q.pop(); int x=u.first,y=u.second; for (int i=0;i<4;++i) { int tx=x+dx[i],ty=y+dy[i]; if (CoordValid(tx,ty) && mp[tx][ty]!=0 && dis[tx][ty]>dis[x][y]+1) { dis[tx][ty]=dis[x][y]+1; Q.push(make_pair(tx,ty)); } } } return dis[e.first][e.second]; }
記錄當前素數的值
每次選擇一個位置,將其該改成另外一個數
檢查新的數是不是素數
至關於移動到一個空位置花費爲一、有守衛的位置花費爲2
直接求最短路?
點數:𝑁∗𝑀≤40000
邊數:𝑁∗𝑀∗2≤80000
直接求最短路可能超時,如何優化?
注意到邊權只有1或2
爲什麼不能直接BFS?
能夠直接BFS求最短路的圖邊權只能是1。
只有邊權爲1才能保證在全部前驅結點都被擴展之後再擴展當前點
如何經過改變這個圖使邊權爲1?
拆點?將每一個點拆成一個入點一個出點?
增長了長度爲0的邊,可能致使錯誤
不能改變原有爲1的邊,如何特殊處理長度爲2的邊?
在到達‘x’點時,強制讓當前點路徑加1,將‘x’改成‘@’,不擴展當前點,使當前點從新入隊。
爲什麼不會影響最終答案?
因爲路徑長度爲1:
其餘點在從新進行擴展到達當前點時,最短路長度≥當前最短路長度+1
所以其餘點沒法更新當前點答案,最終答案所以也不會改變
Bfs本質是貪心?
隊列是有序性,隊首必定是最小的元素,隊列是單增的序列,若是破壞了隊列就不能
d+2-->d+1+1 移動和殺死守衛,殺死守衛至關於從隊首移到隊尾
假設農夫起始位於點3,牛位於5,N=3,K=5,最右邊是6。
如何搜索到一條走到5的路徑?
策略1)深度優先搜索:從起點出發,隨機挑一個方向,能往前走就往前走(擴展),走不動了則回溯。不能走已經走過的點(要判重)。
要想求最優(短)解,則要遍歷全部走法。
策略2)廣度優先搜索:給節點分層。起點是第0層。從起點最少需n步就能到達的點屬於第n層。
第1層:2,4,6
第2層:1,5
第3層:0
擴展時,不能擴展出已經走過的節點(要判重)
可確保找到最優解,可是因擴展出來的節點較多,且多數節點都須要保存,所以須要的存儲空間較大