dfs+剪枝+记忆化搜索(二维01背包)

牛客小白月赛112 E

dfs写的最牢的一局,赛时dp和dfs混着用,一个多小时写了删删了写,结果样例没过。样例过了,剪枝和记忆化不太会,被卡爆

dfs写法

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;
using pii = pair<int,int>;
using db = double;
const int N=105;
int n,m;
int a[N];
vector<int> va,vb;
bool mark=false;
int x;
bool vis[N][N][N];
void dfs(int cnt,int suma,int sumb,int ta,int tb){
    if(mark) return;
    if(suma*sumb>x) return;
    if(suma>ta||sumb>tb) return;
    if(ta==suma&&tb==sumb){
        mark=true;
        return;
    }
    if(cnt>n) return;
    if(vis[cnt][suma][sumb]) return;
    vis[cnt][suma][sumb]=true;
    if(suma+a[cnt]<=ta){
        va.push_back(a[cnt]);
        dfs(cnt+1,suma+a[cnt],sumb,ta,tb);
        if(mark) return;
        va.pop_back();
    }
    if(sumb+a[cnt]<=tb){
        vb.push_back(a[cnt]);
        dfs(cnt+1,suma,sumb+a[cnt],ta,tb);
        if(mark) return;
        vb.pop_back();
    }
    dfs(cnt+1,suma,sumb,ta,tb);
}
int main(){
    std::ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    while(m--){
        cin>>x;
        mark=false;
        for(int i=1;i*i<=x;i++){
            if(x%i)continue;
            int j=x/i;
            va.clear(),vb.clear();
            memset(vis, false, sizeof(vis));
            dfs(1,0,0,i,j);
            if(mark){
                break;
            }
        }
        if(mark){
            cout<<"Yes"<<endl;
            cout<<va.size()<<" "<<vb.size()<<endl;
            for(auto num:va) cout<<num<<" ";
            cout<<endl;
            for(auto num:vb){
                cout<<num<<" ";
            }
            cout<<endl;
        }else{
            cout<<"No"<<endl;
        }
    }
    return 0;
}

dp写法

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;
using pii = pair<int,int>;
using db = double;
const int N=105;
int a[N];
int n,m;
bool dp[N*N][N*N];
int pre[N*N][N*N];
void find(int x,int y,vector<int> &va,vector<int> &vb){
    if(x==0&&y==0) return;
    // cout<<pre[x][y]<<endl;
    // cout<<x<<" "<<y<<endl;
    if(pre[x][y]>0) {
        va.push_back(pre[x][y]);
        find(x-pre[x][y],y,va,vb);
    }
    else {
        vb.push_back(-pre[x][y]);
        find(x,y+pre[x][y],va,vb);
    }
}
int main(){
    std::ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
    cin>>n>>m;
    int sum=0;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        sum+=a[i];
    }
    dp[0][0]=true;
    for(int i=1;i<=n;i++){
        for(int j=100;j>=0;j--){
            for(int k=100;k>=0;k--){
                if(dp[j][k]) continue;
                if(j>=a[i]&&dp[j-a[i]][k]){
                    dp[j][k]=true;
                    pre[j][k]=a[i];
                }
                if(k>=a[i]&&dp[j][k-a[i]]){
                    dp[j][k]=true;
                    pre[j][k]=a[i]*-1;
                }
            }
        }
    }
    // for(int i=0;i<=sum;i++){
    //     for(int j=0;j<=sum;j++){
    //         cout<<dp[i][j]<<" "<<pre[i][j]<<endl;
    //     }
    //     cout<<endl;
    // }
    while(m--){
        int x;
        cin>>x;
        bool mark=false;
        for(int i=1;i*i<=x;i++){
            if(x%i) continue;
            int j=x/i;
            if(dp[i][j]){
                // cout<<dp[i][j]<<endl;
                // cout<<i<<" "<<j<<endl;
                cout<<"Yes"<<endl;
                mark=true;
                vector<int> va,vb;
                find(i,j,va,vb);
                cout<<va.size()<<" "<<vb.size()<<endl;
                for(auto& num:va){
                    cout<<num<<" ";
                }
                cout<<endl;
                for(auto& num:vb){
                    cout<<num<<" ";
                }
                cout<<endl;
            }
            if(mark) break;
        }
        if(!mark){
            cout<<"No"<<endl;
        }
    }
    return 0;
}
全部评论

相关推荐

头像
03-20 22:00
重庆大学 Java
适彼乐土:“他们不行再找你” 最后的底牌吗?有点意思
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务