POJ 3373 Changing Digits 好蛋疼的DP

一开始写的高位往低位递推,发现这样有些时候保证不了第四条要求。于是又开始写高位往低位的记忆化搜索,又发现传参什么的蛋疼的要死。然后又发现高位开始的记忆化搜索就是从低位往高位的递推呀,遂过之。

dp[i][j]记录在i位 且 余数为j时的最优解情况。

dp[i][j].next表示当前的最优解是由哪一种状态转移过来的。

代码又写锉了。。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <cmath>
#include <stack>
#include <map>

#pragma comment(linker, "/STACK:1024000000");
#define EPS (1e-8)
#define LL long long
#define ULL unsigned long long
#define _LL __int64
#define _INF 0x3f3f3f3f
#define Mod 9999991

using namespace std;

struct N
{
    bool mark;
    int ans,dig,next;
}dp[111][10000];

char s[110];

int mod1[110],mod2[110];

void Out(int site,int mod)
{
    if(mod == -1)
        return ;
    printf("%d",dp[site][mod].dig);
    Out(site+1,dp[site][mod].next);

}

int main()
{
    int k,i,j,l;

    while(scanf("%s %d",s+1,&k) != EOF)
    {
        for(i = 1; s[i] != '\0'; ++i)
        {
            for(j = 0; j < k; ++j)
                dp[i][j].mark = false;
        }

        mod1[0] = 0,mod2[0] = 1%k;

        for(i = 1;s[i] != '\0'; ++i)
        {
            mod1[i] = (mod1[i-1]*10 + s[i]-'0')%k;
            mod2[i] = (mod2[i-1]*10)%k;
        }

        int site = strlen(s+1);

        for(i = 0 ;i <= 9 ; ++i)
        {
            if(dp[site][i%k].mark == false)
            {
                dp[site][i%k].mark = true;
                dp[site][i%k].ans = (i == s[site]-'0' ?  0 : 1);
                dp[site][i%k].dig = i;
                dp[site][i%k].next = -1;
            }
            else
            {
                if((i == s[site]-'0' ?  0 : 1) < dp[site][i%k].ans)
                {
                    dp[site][i%k].ans = (i == s[site]-'0' ?  0 : 1);
                    dp[site][i%k].dig = i;
                }
                else if((i == s[site]-'0' ?  0 : 1) == dp[site][i%k].ans && i <= dp[site][i%k].dig)
                {
                    dp[site][i%k].dig = i;
                }
            }
        }

        int mod;
        int len = strlen(s+1);

        for(--site ; site >= 1 ; --site)
        {
            mod = 0;
            for(i = (site == 1 ? 1 : 0);i <= 9; ++i)
            {
                for(j = 0;j < k; ++j)
                {
                    if(dp[site+1][j].mark == true)
                    {
                        if(dp[site][(mod + i*mod2[len-site] + j)%k].mark == false)
                        {
                            dp[site][(mod + i*mod2[len-site] + j)%k].mark = true;
                            dp[site][(mod + i*mod2[len-site] + j)%k].ans = dp[site+1][j].ans+(s[site]-'0' == i ? 0 :1);
                            dp[site][(mod + i*mod2[len-site] + j)%k].dig = i;
                            dp[site][(mod + i*mod2[len-site] + j)%k].next = j;
                        }
                        else
                        {
                            if(dp[site+1][j].ans+(s[site]-'0' == i ? 0 :1) < dp[site][(mod + i*mod2[len-site] + j)%k].ans)
                            {
                                dp[site][(mod + i*mod2[len-site] + j)%k].ans = dp[site+1][j].ans+(s[site]-'0' == i ? 0 :1);
                                dp[site][(mod + i*mod2[len-site] + j)%k].dig = i;
                                dp[site][(mod + i*mod2[len-site] + j)%k].next = j;
                            }
                            else if(dp[site+1][j].ans+(s[site]-'0' == i ? 0 :1) == dp[site][(mod + i*mod2[len-site] + j)%k].ans && i < dp[site][(mod + i*mod2[len-site] + j)%k].dig)
                            {
                                dp[site][(mod + i*mod2[len-site] + j)%k].dig = i;
                                dp[site][(mod + i*mod2[len-site] + j)%k].next = j;
                            }
                        }
                    }
                }
            }
        }
        Out(1,0);
        puts("");
//        cout<<len<<endl;
//        for(i = 1;i <= len; ++i)
//        {
//            for(j = 0;j < k; ++j)
//            {
//                if(dp[i][j].mark)
//                    printf("%2d ",dp[i][j].next);
//                else
//                    printf("   ");
//            }
//            puts(" * ");
//        }
//
//        puts("");
//
//        for(i = 1;i <= len; ++i)
//        {
//            for(j = 0;j < k; ++j)
//            {
//                if(dp[i][j].mark)
//                    printf("%2d ",dp[i][j].dig);
//                else
//                    printf("   ");
//            }
//            puts(" * ");
//        }
//
//        puts("");
//
//
//        for(i = 1;i <= len; ++i)
//        {
//            for(j = 0;j < k; ++j)
//            {
//                if(dp[i][j].mark)
//                    printf("%2d ",dp[i][j].ans);
//                else
//                    printf("   ");
//            }
//            puts(" * ");
//        }

    }

    return 0;
}

POJ 3373 Changing Digits 好蛋疼的DP,布布扣,bubuko.com

时间: 2024-08-05 11:39:37

POJ 3373 Changing Digits 好蛋疼的DP的相关文章

POJ 3373 Changing Digits

题目大意: 给出一个数n,求m,使得m的长度和n相等,能被k整除.有多个数符合条件输出与n在每位数字上改变次数最小的.改变次数相同的输出大小最小的.  共有两种解法:DP解法,记忆化搜索的算法. 以后会更新记忆化搜索. 1.DP解法: 解题思路: DP[i][j]表示数n的前i位除以k余j最小改变几位. DP[len][0]就表示数n被k整除最小改变几位. 根据这个关系从后向前遍历DP数组可以找出所有满足条件的数的路径. 再根据关系从前往后输出.  下面是代码: #include <stdio.

poj 3373

Changing Digits Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 2960   Accepted: 952 Description Given two positive integers n and k, you are asked to generate a new integer, say m, by changing some (maybe none) digits of n, such that th

POJ3373:Changing Digits(记忆化)

Description Given two positive integers n and k, you are asked to generate a new integer, say m, by changing some (maybe none) digits of n, such that the following properties holds: m contains no leading zeros and has the same length as n (We conside

POJ 2411 Mondriaan&#39;s Dream(状压DP)

http://poj.org/problem?id=2411 求一个n*m矩阵用1*2方块去填满的情况有几种 思路:状压dp,先预处理那些状态之间能互相到达,情况就几种,上一个两个1,下一个状态也两个1,上一个为0,下一个必须为1,还有一种是上一个为1,下一个为0的情况 然后就一层层往后递推即可 代码: #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; int

TOJ 2294 POJ 3286 How many 0&#39;s? 数位dp

http://acm.tju.edu.cn/toj/showp2294.html http://poj.org/problem?id=3284 题外话:集训结束,回学校了.在宿舍看了这题,没什么好想法,去洗澡了.转了两个澡堂都特么没开..倒是在路上把这题想了.用回自己的电脑,不得不说苹果的字体渲染,真心高一个等级. 题意:给定两个数a和b,从a写到b,问一共写了多少个0. 分析:当然先转化为求0..a写多少个0.网上有更简单的做法,就是枚举每位作为0,则如果这一位本来是0,左边取1..a-1(不

POJ 3249 Test for Job 拓扑排序+DP

http://poj.org/problem?id=3249 题意: 给一个有向无环图DAG(不一定联通),每个点有权值,入度为0的点为起点,出度为0的点为终点,选择一个起点走到一个终点,使得路上的权和最大. 分析: dp[to] = max(dp[from]) + value[to],然后先拓扑排序保证状态正确转移即可,终点做标记,如果是终点则尝试更新答案. update:因为点权可以为负,所以程序里用dp[i] == -1表示未访问过该点是有问题的,不过没有遇上会卡掉这种情况的数据=.= 1

poj 3254 Corn Fields ,状态压缩DP

题目链接 题意: 一个矩阵里有很多格子,每个格子有两种状态,可以放牧和不可以放牧,可以放牧用1表示,否则用0表示,在这块牧场放牛,要求两个相邻的方格不能同时放牛,即牛与牛不能相邻.问有多少种放牛方案(一头牛都不放也是一种方案) state[i] 表示对于一行,保证不相邻的方案 状态:dp[i][ state[j] ]  在状态为state[j]时,到第i行符合条件的可以放牛的方案数 状态转移:dp[i][ state[j] ] =Sigma dp[i-1][state'] (state'为符合条

POJ 2411 Mondriaan&#39;s Dream ——状压DP 插头DP

[题目分析] 用1*2的牌铺满n*m的格子. 刚开始用到动规想写一个n*m*2^m,写了半天才知道会有重复的情况. So Sad. 然后想到数据范围这么小,爆搜好了.于是把每一种状态对应的转移都搜了出来. 加了点优(gou)化(pi),然后poj上1244ms垫底. 大概的方法就是考虑每一层横着放的情况,剩下的必须竖起来的情况到下一层取反即可. 然后看了 <插头DP-从入门到跳楼> 这篇博客,怒抄插头DP 然后16ms了,自己慢慢YY了一下,写出了风(gou)流(pi)倜(bu)傥(tong)

poj 2411 Mondriaan&#39;s Dream 状压dp入门

题意: 求h*w的矩形被1*2的小矩形覆盖的方案数. 分析: 状压dp入门,<挑战程序设计竞赛>上讲的很好,好几天才看懂. 代码: #include <iostream> using namespace std; __int64 ans[16][16]; int n,m; __int64 dp[2][1<<16]; __int64 solve() { int i,j,used; memset(dp,0,sizeof(dp)); __int64 *crt=dp[0],*n