[典题]

codeforces 789E. The Great Mixing(经典,dp,状态图建立)

void bfs()
{
    queue<int>q;
    for(int i=0;i<=1000;i++)
    {
        if(st[i])
        {
            v.pb(n-i);
            int x=n-i+1000;//这里最主要的作用是标记,n-i可能会越界,加1000偏移量
            f[x]=1;
            if(x==1000)break;
            q.push(x);
        }
    }
    while(!q.empty())
    {
        auto t=q.front();
        q.pop();
        for(int i=0;i<v.size();i++)
        {
            int w=t+v[i];
            if(w>=0&&w<=2000&&f[w]>f[t]+1)
            {
                f[w]=f[t]+1;
                if(w==1000)break;
                q.push(w);
            }
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin>>n>>k;
    memset(f,INF,sizeof f);
    memset(st,0,sizeof st);
    for(int i=0;i<k;i++)
    {
        int x;
        cin>>x;
        st[x]=1;
    }
    bfs();
    if(f[1000]>=INF)
    {
        cout<<-1<<endl;
        return 0;
    }
    else
    {
        cout<<f[1000]<<endl;
    }
    return 0;
}

A. Cut Ribbon

完全背包问题,给出三个可以裁剪的长度,看最多能裁剪多少段

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin>>n;
    memset(f,-0x3f,sizeof f);
    f[0]=0;
    for(int i=1;i<=3;i++)
    {
        int x;
        cin>>x;
        for(int j=x;j<=n;j++)
            f[j]=max(f[j],f[j-x]+1);
    }
    cout<<f[n]<<endl;
    return 0;
}

 

Bigger is Better UVA - 12105 (数位dp)

i是火柴个数,j是每次从右取的数字的总值%m的余数,dp[][]=进行的次数

输出时从大到小减去次数-1输出对应的k值,应用pre记录此时的k

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int cnt=1;
    while(cin>>n&&n)
    {
        cin>>m;
        memset(f,-1,sizeof f);
        for(int i=0;i<=n;i++)
            f[i][0]=0;
        int ans=-1;
        for(int i=1;i<=n;i++)//枚举火柴
            for(int j=0;j<m;j++)//j是枚举所有0~9的余数
                for(int k=9;k>=0;k--)//枚举从大开始的个位拼的数字
                    if(i>=num[k])
                    {
                        if(f[i-num[k]][(j*10+k)%m]>=0&&f[i][j]<(f[i-num[k]][(j*10+k)%m]+1))
                        {
                            f[i][j]=f[i-num[k]][(j*10+k)%m]+1;
                            pre[i][j]=k;
                        }
                    }
        ans=f[n][0];
        cout<<"Case "<<cnt++<<": ";
        if(ans<=0)
        {
            cout<<-1<<endl;
            continue;
        }
        else
        {
            int x=n,y=0;
            for(int i=ans-1;i>=0;i--)
            {
                int t=pre[x][y];
                cout<<t;
                x-=num[t];
                y=(y*10+t)%m;
            }
            cout<<endl;
        }
    }
    return 0;
}

 遗迹探险(线性dp)

因为k传送门的数量很少,所以可以枚举传送门的位置,正着做一遍线性dp,反着做一遍,那么我们加上同一个传送门的位置的时候,可以直接进行取max

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin>>n>>m;
    vector<vector<int>>f(n+10,vector<int>(m+10,-INF)),g(n+10,vector<int>(m+10,-INF));
    vector<vector<int>>a(n+10,vector<int>(m+10));
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            cin>>a[i][j];
    f[0][1]=0;
    f[1][0]=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            f[i][j]=max(f[i-1][j],f[i][j-1])+a[i][j];
    g[n][m+1]=0;
    g[n+1][m]=0;
    for(int i=n;i>=1;i--)
        for(int j=m;j>=1;j--)
            g[i][j]=max(g[i+1][j],g[i][j+1])+a[i][j];
    int t;
    cin>>t;
    while(t--)
    {
        int k;
        cin>>k;
        vector<PII>c(k);
        for(int i=0;i<k;i++)
            cin>>c[i].first>>c[i].second;
        int ans=f[n][m];
        for(int i=0;i<k;i++)
            for(int j=0;j<k;j++)
            {
                if(i==j)continue;
                int aa=c[i].first,bb=c[i].second;
                int cc=c[j].first,dd=c[j].second;
                ans=max(ans,f[aa][bb]+g[cc][dd]);
            }
        cout<<ans<<endl;
    }
    return 0;
}

 Codeforces Round 871 (Div. 4)F. Forever Winter

给定一个图,请你求出 x,y ,满足在图上的某一个点 ver(中心点) 连接了 x 个点,那些与 ver 相连的点,除 ver 以外都与 y 个结点相连。

思路:

1.我们暴力枚举每个x=cnt[i](cnt[a]++存的是a点对应的点数),这时候判断剩下的点是否满足y==(n - 1 - x) / x,还要判断x<=1&&<=1

2.这时候我们根本不用和中心点相连的x,只需要进行从x点出发,每次遇到的点++后,最终边都遍历结束后判断num==tmp即可,就可以判断y是否成立,成立直接输出就好了

void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void dfs(int u)
{
    st[u] = 1;
    for (int i = h[u]; i != -1; i = ne[i])
    {
        int j = e[i];
        if (st[j])continue;
        tmp++;
        dfs(j);
    }
}
bool check(int ver, int num)
{
    tmp = 0;
    dfs(ver);
    return tmp == num;
}
void solve()
{
    memset(h, -1, sizeof h);
    memset(cnt, 0, sizeof cnt);
    idx = 0;
    cin >> n >> m;
    for (int i = 1; i <= m; i++)
    {
        int a, b;
        cin >> a >> b;
        add(a, b);
        add(b, a);
        cnt[a]++;
        cnt[b]++;
    }
    for (int i = 1; i <= n; i++)
    {
        int x = cnt[i], y = (n - 1 - x) / x;
        if (x <= 1 || y <= 1)continue;
        if (y * x != n - 1 - x)continue;
        bool ok = true;
        memset(st, false, sizeof st);
        st[i] = true;
        for (int j = h[i]; j != -1; j = ne[j])
        {
            int u = e[j];
            if (!check(u, y))
            {
                ok = false;
                break;
            }
        }
        if (ok)
        {
            cout << x << ' ' << y << endl;
            return;
        }
    }
}

 

posted @ 2023-05-10 20:37  Thecode_Wm  阅读(42)  评论(0)    收藏  举报