魔術球問題

2022-08-13 08:00:20 字數 1924 閱讀 5467

曾經在模擬賽的時候做過弱化版,不需要輸出方案。

其實加強版因為資料範圍很小,模擬做也未嘗不可,暴力算出n=55時最終答案也只有1567,拿二維陣列存一下方案即可。

當然,這個題是由網路流做法的,雖然我的網路流做法只是模擬了乙個貪心的過程。

貪心的正確性證明就請移步我的弱化版題解好啦:

對於乙個球,有兩種放法,獨佔一行或是連到乙個柱子上。

把點拆成兩個,記為x1與x2,兩個點之間不連邊,拆成的兩個點處理不同情況,為保證合法,向匯點連一條邊。

對於獨佔一行的情況,x1連向源點,

對於連到乙個柱子上,其中能和它組成平方數的點y,x2向y1連一條邊即可。

設i^i為他們的和。列舉i,i的範圍是(sqrt(num),sqrt(num<<1))

顯然,i如果<=sqrt(num)的話,那麼i*i-num<=0,顯然不存在這樣的球。

如果 i*i>=num<<1,那麼這個球顯然要在第num個球之後放下,不在此時的考慮範圍之內,由此確定i的範圍。

建完邊之後,跑最大流即可,isap太難寫,於是就用dinic了。

如果第num個點能夠放在其他的柱子上的話,那麼必然存在這樣乙個點a,有這樣三條邊:

s->a1 a1->num2 num2->t 所以在新圖中,最大流不為零。

否則說明所有能與num組成平方數的數字a,上方都已經放了其他的球,圖上s->a1這條邊一定已經有1的流量流過,此時最大流為0,num必須另找一根柱子放下。

記錄每根柱子的開頭,dfs時記錄它連向的點即可。

ps:打dfs的時候少打了一行,而且是最要緊的一行。。。寫錯之後,不但把建邊搞亂了,查方案的時候也沒法正常查。

(不知道怎麼寫《gg記錄》,就寫到這裡好了)

gg記錄鏈結(欣賞一下蒟蒻的zz錯誤吧):

#include#include

#include

#include

#include

using

namespace

std;

const

int inf=(1

<<30

);int n,tot,num,s,t=50003,cnt=1

;struct

edge

e[100005

];int l[100005],dis[100005],head[100005

];int nxt[100005],vis[100005

];void add(int u,int

v)int dfs(int x,int

f) }

return0;

}int

bfs()

}return

dis[t];

}int

dinic()

}return

ans;

}int

main()

if(!dinic()) l[++tot]=num;

}num--;

printf(

"%d\n

",num);

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

printf("\n

");}

return0;

}

魔術球問題

列舉放的球,先假設新建柱子,拆成兩個點,第乙個點連s,表示後面還可以放 第二個連t表示放到其他柱子上 再列舉放過的數和它是否組成完全平方數,列舉的數的第乙個點向它的第二個點連邊,表示這個球可以放到其他球上,容量都為一 每次跑最大流出來的表示會消掉的柱子個數,如果此時球 消去的比n大則break輸出答...

魔術球問題

題目描述 題解 個人認為網路流二十三題中比較有意思的一道。先列舉球數。每加乙個球,從 s 向 xi 連一條容量為 1 的邊,從 yi 向 t 連一條容量為 1 的邊。然後從 xi 向滿足 i j 為完全平方數的 yj 連容量為 1 的邊。在殘餘網路上跑 ek 或 dinic 如果得到的最大流為 0 ...

魔術球問題 題解

具體的數學關係還是不會證,除了能打表發現球數規律外,內在原理也弄不清楚。戳很難想象是一道網路流。第一感是數學。但是看到資料範圍比較小,估計可以暴力dp。又發現,狀態轉移比較難,狀態調整比較多,dp估計難設,又看到資料範圍又小於dp通常可做範圍,所以用同樣以規劃和狀態設計為關鍵字的,狀態調整能力更強的...