題目:nyoj 1078 漢諾塔(四)
分析:做這個題目的時候是在圖論的題目裡面看到的,到時讀了題目推了一下,發現好像有點規律,試了一下果然過了。
後來看了一下數據,才50,那麼試了一下模擬,也過了。
好像zoj有一道題目卡模擬,模擬的時候必須貪心一下才能過
這道題出題人的意圖在於考大家的:二分圖最小路徑覆蓋。
把每一個球看做一個點,然後如果兩個和為平方數的話就給這兩個點之間連接一條邊,然後用一個特殊的匹配算法,類似於匈牙利算法,但是每次找匹配的時候加入一條邊上連接的有匹配的話就不能匹配,最後求一個最大匹配就好了。這個題目50個點,當然要預處理成離線的。
如果每次都建圖跑的話時間復雜度是非常高的,所以我們可以用標記的方法,如果匹配過的就不用再匹配了。這樣能降低很多時間,但是還是很長。
找規律代碼:
#includeint ans[55]; void isit() { ans[1]=1,ans[2]=3; for(int i=3;i<51;i++) ans[i]=ans[i-1]+(i+1)/2 * 2; } int main() { int T,n;isit(); scanf("%d",&T); for(;T--&&scanf("%d",&n);printf("%d\n",ans[n])); }
#include#include #include using namespace std; stack st[60]; int ans[60]; void isit() { int tmp=1,i=1; while(i<55) { int ok=0; for(i=1;!st[i].empty();i++) { int zhi = st[i].top()+tmp; int sq=sqrt(zhi); if(sq * sq == zhi) { st[i].push(tmp); ok=1; break; } } if(!ok){ st[i].push(tmp); ans[i]=tmp-1; } tmp++; } } int main() { int T,n;isit(); scanf("%d",&T); for(;T--&&scanf("%d",&n);printf("%d\n",ans[n+1])){} }
#include#include #include #include using namespace std; const int N = 60; const int M = 1500; int ans[N]; bool ok[M*2+10]; bool mp[M][M]; int mx[M],my[M]; //mx保存正向邊 my保存反向邊 bool used[M]; // bool dfs(int v) { for (int u = 1; u < v; ++u) //優化 if (mp[v][u] && !used[u]) { used[u] = true; if (my[u] == -1 || dfs(my[u])) { //一直向下找 my[u] = v; mx[v] = u; return true; } } return false; } int Max_Pi(int ans,int n) //最大匹配 { for(int i=1;i<=n;i++) { if(mx[i]<0){ memset(used,false,sizeof(used)); if(dfs(i)) ans++; } } return ans; } void Min_Road() //最小路徑覆蓋 { memset(mx,-1,sizeof(mx)); //優化 memset(my,-1,sizeof(my)); for(int i=1;i*i<=2*M;i++) ok[i*i]=true; ans[1]=1; int tmp=0; for(int i=2;i<=M;i++) { for(int j=1;j55) break; } // for(int i=1;i<=50;i++) // printf("%d ",ans[i]); } int main() { int T,n;Min_Road(); scanf("%d",&T); for(;T--&&scanf("%d",&n);printf("%d\n",ans[n])){} }