題解 亞瑟王的宮殿

2022-06-19 18:27:16 字數 3213 閱讀 3637

在此之前,該題已經有很多題解,但它們大多是列舉國王周圍\(5\times 5\)的範圍(玄學貪心?),最後計算最小距離。

雖然能\(ac\),但其實這種做法是不嚴謹的( 詳見巨佬的hack資料 )

然而將\(5\times 5\)的範圍擴大至\(r\times c\)的範圍後,時間複雜度過大。那麼,這道題真的無解了嗎?

蒟蒻的我用\(spfa\)

(在此稀疏圖中,顯然不怕被卡)在正確的結果和正確的時間複雜度內\(ac\)了此題(而且過了\(hack\)資料)。

題目不再闡述。題目傳送門

這道題求的是所有騎士以及國王到某集合點的最小距離(任意騎士與國王匯合後,可以帶著國王一起走,並且只算乙個人的距離)。

集合點是哪乙個?不知道。不知道就列舉

與其它題解無異,看到範圍十分小的\(r、c\)後,毅然選擇列舉集合點。

列舉後,相當於已經知道了集合點,求騎士和國王從原所在地到該點的最小距離和。

這個可以反過來看,也就是從集合點出發,求出騎士和國王從集合點到騎士和國王原所在地的距離的最小值。

顯然,上述兩者是等價的。因此,我們可以用最短路演算法直接求出最小的距離之和。這裡使用\(spfa\)。(當然,\(dijkstra\)也可以,而且更穩定)沒事,這題是卡不了\(spfa\)的。

重點來了,敲黑板(此思路與其它題解最大的不同在這裡)

定義\(dis(x, y, 0)\)表示集合點到點\((x,y)\)的最小距離(最少步數,不帶國王)。

定義\(dis(x, y, 1)\)表示集合點到點\((x,y)\)的最小距離(最少步數,此時在點\((x,y)\),騎士已經帶上了(或者是正在帶著)國王)

考慮如何轉移。

對於\(dis(x,y,0)\)這個狀態,可以作兩種轉移:

1.不帶國王,繼續走自己的路。

可以轉移出八個狀態(即騎士走的八個"日"字,這裡不作列舉),設八個狀態為\(dis(ex, ey, 0)\)。因為騎士轉移到這個狀態只需要一步,所以權值為\(1\)。

轉移方程為\(dis(ex, ey, 0) =\min\)

2.站在原地,等國王過來,然後帶上國王

可以轉移出乙個狀態,設國王走過來的步數為\(val\)(\(val\)可以\(\theta (1)\)求出)。轉移的狀態為\(dis(x,y,1)\)

轉移方程為\(dis(x,y,1)=\min\)

對於\(dis(x,y,1)\)這個狀態,可作一種轉移(畢竟騎士已經帶著國王私奔去了,不可能丟下國王自己跑吧)

1.同上,同樣是可以轉移出八個狀態,轉移方程不寫了。

\(last\quad but\quad not\quad least\)等等,還沒完

\(spfa\)跑完後,我們得到了\(dis(x,y,z)\)陣列,但題目要求的是距離和的最小值。

簡單,將最小值累加即可。等等,那麼問題來了,哪位騎士帶國王\(???\)

也就是說,我們需要找到乙個騎士,累加他的\(dis(x,y,1)\),同時累加其它騎士的\(dis(x,y,0)\),使得總和最小。

容易證明,\(dis(x,y,0)\leq dis(x,y,1)\)

乙個人走總是比帶著國王走輕鬆

因此,我們只需要列舉每個\((x,y)\),求出\(dis(x,y,1)-dis(x,y,0)\)的最小值,然後加上所有\(dis(x,y,0)\)就是最小距離了。

最差時間複雜的\(\theta (r^2c^2)\)

時間都花在列舉上了,穩穩地過,不需要卡常。

我知道大家喜歡看這個

有注釋哦。

#includeusing namespace std;

const int maxr = 45, maxc = 30, inf = 1e6 + 7;

int r, c, map[maxr][maxc], kingx, kingy;

int x[8] = , y[8] = ;

struct node;

queue< node > q;

int abs(int x)

int spfa(int x,int y); bool vis[maxr][maxc][2] = {};//初始化dis,vis陣列(spfa常規操作)

for(int i=1; i<=r; i++)//初始化dis陣列,同樣是常規操作

for(int j=1; j<=c; j++)

dis[i][j][0] = dis[i][j][1] = inf;

node t;

if(x == kingx and y == kingy) dis[x][y][1] = 0, t.king = true;//如果集合點的位置是國王的位置(不用考慮國王的移動),初始狀態就是dis[x][y][1]

else dis[x][y][0] = 0, t.king = false;//如果集合點的位置不是國王的位置,需要考慮國王的移動,初始狀態是dis[x][y][0]

t.x = x, t.y = y;

q.push(t);//入隊,常規操作

vis[x][y][t.king] = true;//標記,常規操作

while(!q.empty())

}} if(!flag)

}} vis[dx][dy][flag] = false;

} int minu = inf, cnt = 0;//最短路跑完後,算出最短的總距離

//容易證明,騎士所在的點的狀態dis[x][y][1]>=dis[x][y][0],要使總距離最小,只需要找最小的(dis[x][y][1]-dis[x][y][0]),最後加上所有騎士的距離dis[x][y][0]即可

for(int i=1; i<=r; i++)

for(int j=1; j<=c; j++)

if(map[i][j] == 1) minu = min(minu, dis[i][j][1] - dis[i][j][0]), cnt += dis[i][j][0];

return cnt+minu;

}int main()

int ans = inf;//初始化

for(int i=1; i<=r; i++)

for(int j=1; j<=c; j++)

ans = min(ans, spfa(i, j));//列舉集合點,spfa求最短距離

if(ans == inf) printf("0");

else printf("%d", ans);

return 0;

}

usaco3 3 4亞瑟王的宮殿

對於騎士帶王去會合的情況,列舉王的原位置和八個方向,也就是說王和騎士的匯合點相對於王的原位置為上下左右或者斜45度方向。比如在8 8的棋盤上,王的位置用k表示,需要列舉的帶王的點用1表示,其餘點用0表示則有下圖 0 0 1 0 0 1 0 0 1 0 1 0 1 0 0 0 0 1 1 1 0 0 ...

概率 亞瑟王

題目描述 小 k 不慎被 ll 邪教 了,程度深到他甚至想要從亞瑟王邪教中脫坑。他決定,在脫坑之前,最後再來打一盤亞瑟王。既然是最後一戰,就一定要打得漂亮。眾所周知,亞瑟王是乙個看臉的遊戲,技能的發動都是看概率的。作為乙個非洲人,同時作為乙個前 oier,小 k 自然是希望最大化造成傷害的期望值。但...

賽後題解 真假亞瑟王(數論)

c.真假亞瑟王 題目描述魔術師梅林在水晶球中預見了莫德雷德的叛逆,她決定在在莫德雷德叛逆之前採取乙個有效的策略保護亞瑟王。具體做法如下 使用魔法將亞瑟王複製成n份,當然,其中只有乙個使真的。她認為這樣就能有效的保護亞瑟王不被殺死。為了自己能最終找到亞瑟王,她將所有的亞瑟王按1 n編號,並設定了乙個密...