第十二屆北航程式設計競賽決賽網路同步賽: 浪哥的煩惱
阿新 • • 發佈:2019-01-02
題目連結:https://biancheng.love/problem/587/index
題目描述
最近學校大檢查,要求上課認真聽講,這讓浪哥很是煩惱,因為這樣他就不能上課刷題了。但經過不懈的觀察,他發現領導檢查是有一定的規律的。不妨把每層樓的教室看成一排,從 1 到 n 標號,領導每檢查完一個教室,就會從相鄰的一個或兩個教室中選擇一個繼續檢查,一個教室可能被檢查不止一次。
已知時刻 0
領導在 1
號教室,從 i
號教室走到 i+1
號教室需要 ti
時間,從 i+1
號教室走到 i
號教室也需要 ti
時間 (i=1,2,⋯,n−1),檢查一個教室的時間極短可忽略不計,放學時刻為
m
。
浪哥想要知道,放學之前(包括 m )的哪些時刻,領導是不可能檢查到他所在的 n 號教室的。
輸入
第一行包含一個正整數 T ,表示有 T 組測試資料。
接下來依次給出每組測試資料。對於每組測試資料:
第一行包含兩個正整數 n 和 m。
第二行包含 n−1個正整數 t1,t2,⋯,tn−1。
1≤T≤200,2≤n≤100,1≤m≤500,1≤ti≤m
輸出
對於每組資料輸出一行,包含一些正整數,按升序給出,表示 n 號教室不可能被檢查的時刻。
對於本題,輸出中在一行的每個整數之間用恰好一個空格隔開,不能有其他額外空格。
輸入樣例
1
3 10
2 3
輸出樣例
1 2 3 4 6 7 8 10
樣例解釋
在放學前,領導有兩種不同的檢查方式會檢查到 3
號教室,分別是 1 -> 2 -> 3
和
1 -> 2 -> 1 -> 2 -> 3
,其中到達 3
號教室的時刻分別為 5
和
9
。
這道題有兩種做法,第一種就是直接用母函式,三個for迴圈,這個for也不是全部迴圈,而且範圍較小,所以不會超時,程式碼如下:
// >File Name: bianchenglove1.cpp // > Author: Webwei #include<iostream> #include<algorithm> #include<cstring> using namespace std; int n,m,vis[505]; int a[105]; int main() { ios::sync_with_stdio(0); cin.tie(0); int t; cin>>t; while(t--) { cin>>n>>m; memset(vis,0,sizeof(vis)); int s=0; for(int i=1;i<n;i++) { cin>>a[i]; s+=a[i]; a[i]*=2; if(s>m) break; } if(s<=m){ vis[s]=1; for(int i=1;i<n;i++){ for(int j=s;j<m;j++){ for(int k=a[i];k+j<=m;k+=a[i]) { if(!vis[k+j]) vis[k+j]=vis[j]; } } } } int flag=0; for(int i=1;i<=m;i++) { if(!vis[i]){ if(flag) cout<<" "; else flag=1; cout<<i; } } cout<<'\n'; } return 0; }
還有另一種就是dp,記憶化搜尋
#include<bits/stdc++.h>
using namespace std;
int tim[505];
int h=0;
int ans[505];
int n,m;
int us[105][505];
int dfs(int k,int t)
{
if(k==n&&t<=m) ans[t]=1;
if(t>m||us[k][t]) return 0;
if(k!=n) dfs(k+1,t+tim[k]);
if(k!=1) dfs(k-1,t+tim[k-1]);
us[k][t]=1;
}
int main()
{
int t;
cin >> t;
while( t-- )
{
cin >> n >> m ;
fill(ans , ans + m + 1 , 0);
for(int i=1;i<n;i++)
{
cin>>tim[i];
}
memset(us,0,sizeof(us));
dfs(1,0);
int flag=0;
for(int i=1;i<=m;i++){
if(ans[i]==0){
if(flag==0){
cout<<i;
flag=1;
}else{
cout<<" "<<i;
}
}
}
cout<<'\n';
}
}