網路流24題 魔術球問題

2021-08-27 23:41:34 字數 1351 閱讀 1363

列舉答案轉化為判定性問題,然後最小路徑覆蓋,可以轉化成二分圖最大匹配,從而用最大流解決。

列舉答案a,在圖中建立節點1..a。如果對於i具體方法可以順序列舉a的值,當最小路徑覆蓋數剛好大於n時終止,a-1就是最優解。

由於是順序放球,每根柱子上的球滿足這樣的特徵,即下面的球編號小於上面球的編號。抽象成圖論,把每個球看作乙個頂點,就是編號較小的頂點向編號較大的頂點連線邊,條件是兩個球可以相鄰,即編號之和為完全平方數。每根柱子看做一條路徑,n根柱子要覆蓋掉所有點,乙個解就是乙個路徑覆蓋。

最小路徑覆蓋數隨球的數量遞增不遞減,滿足單調性,所以可以列舉答案(或二分答案),對於特定的答案求出最小路徑覆蓋數,乙個可行解就是最小路徑覆蓋數等於n的答案,求出最大的可行解就是最優解。本問題更適合列舉答案而不是二分答案,因為如果順序列舉答案,每次只需要在殘量網路上增加新的節點和邊,再增廣一次即可。如果二分答案,就需要每次重新建圖,大大增加了時間複雜度。

#include using namespace std;

const int maxn = 500005;

const int maxm = 1100000;

const int inf = 0x3f3f3f3f;

struct edge1

;struct dinic

edges.clear();

} void addedge(int from,int to,int cap)

); edges.push_back((edge1));

m = edges.size();

g[from].push_back(m - 2);

g[to].push_back(m - 1);

} bool bfs()

}} return vis[t];

} int dfs(int x,int a)

}return flow;

} int maxflow(int s,int t)

return flow;

}}din;

bool vis[30000],vis1[30000];

int to[30000];

void init()

}int main(void)

cnt += din.maxflow(s,t);

if(cur - cnt > n) break;

}printf("%d\n",cur - 1);

for(int i = 0; i < din.edges.size(); i++)

}for(int i = 1; i <= cur - 1; i++)

printf("\n");}}

return 0;

}

魔術球問題(網路流24題)

假設有n根柱子,現要按下述規則在這n根柱子中依次放入編號為1,2,3,的球。1 每次只能在某根柱子的最上面放球。2 在同一根柱子中,任何2個相鄰球的編號之和為完全平方數。試設計乙個演算法,計算出在n根柱子上最多能放多少個球。例如,在4 根柱子上最多可放11 個球。對於給定的n,計算在n根柱子上最多能...

網路流24題 魔術球問題

以珠子為點,滿足條件就兩兩連邊 那麼就是讓你求n條路徑最多能覆蓋多少節點。眾所周知,最小邊覆蓋 點總數 最大匹配 不會看這裡link 於是拆點跑二分圖即可 大概就是s向x連邊 滿足條件的點k向x 連邊 x 向t連邊 有兩種方式 1.我們輪流加點,每次在殘量網路跑最大流就可以了 2.我們二分答案,每次...

網路流24題 魔術球問題

題目描述 將所有球看做點,在每根柱子上放球就是下邊的點向上邊的點連邊,可以連邊的條件是兩球編號之和為完全平方數。再把這n跟柱子看做是n條路徑,問題也就轉換成了用n條路徑覆蓋所有的點,也就是最小路徑覆蓋問題。最小路徑覆蓋數隨著點數的增加不會遞減,滿足二分的性質,但是二分時要重新構圖,所以不如直接順序列...