codeforces1202B You Are Given a Decimal String... 记忆化搜索或Floyd最短路算法

网址:http://codeforces.com/problemset/problem/1202/B

题意:

这个题真的挺绕的,草(中日双语),就是给出一串序列,然后你可以往里面填数,使得填数后的序列可以被$x-y$计数器输出。$x-y$计数器的工作方式是:初始是$0$,每一步加上$x$或者加上$y$,然后输出对$10$取余的数。输出$0<x,y<10$的$x-y$计数器下需要添加的字符数最小值,若无法满足输出$-1$。

题解:

草,比赛时靠着网上的资料一步步写出的记忆化搜索的方法,想不出正解是转化成最短路。

一、dfs记忆化搜索

对于不断对$10$取余的序列,不超过$10$轮就会出现相同的数字,因此,$dfs$最多只有$10$轮,遇到重复的数字时,如果搜索的层数小于原来保存的层数,则更新,大于等于则返回保证了搜索结果的层数都是最小值。然后字符串的一个字符到下一个字符相当于状态转移,直接读取保存下来的状态即可。

AC代码:$(600ms)$

#include <bits/stdc++.h>
using namespace std;
int dp[15][15][15],res[15][15];
char str[2000005];
int x,y;
void dfs(int div,bool mode,int cur)
{
    if(!mode)
    {
        cur=(cur+x)%10;
        if(dp[x][y][cur]!=-1)
            if(div>=dp[x][y][cur])
                return;
        dp[x][y][cur]=div;
        dfs(div+1,0,cur);
        dfs(div+1,1,cur);
    }
    else
    {
        cur=(cur+y)%10;
        if(dp[x][y][cur]!=-1)
            if(div>=dp[x][y][cur])
                return;
        dp[x][y][cur]=div;
        dfs(div+1,0,cur);
        dfs(div+1,1,cur);
    }
}
void init()
{
    memset(dp,-1,sizeof(dp));
    for(int i=0;i<10;++i)
        for(int j=0;j<10;++j)
        {
            x=i,y=j;
            dfs(0,0,0);
            dfs(0,1,0);
        }
}
int cal(int x,int y,int len)
{
    if(len==1)
        return 0;
    int ans=0;
    for(int i=1;i<len;++i)
    {
        int tmp;
        int dis=str[i]-str[i-1];
        while(dis<0)
            dis+=10;
        tmp=dp[x][y][dis];
        if(tmp==-1)
            return -1;
        else
            ans+=tmp;
    }
    return ans;
}
int main()
{
    init();
    scanf("%s",str);
    int len=strlen(str);
    for(int i=0;i<10;++i)
        for(int j=0;j<10;++j)
            res[i][j]=cal(i,j,len);
    for(int i=0;i<10;++i)
        for(int j=0;j<10;++j)
            printf("%d%c",res[i][j],(j==9?‘\n‘:‘ ‘));
    return 0;
}

二、floyd算法

状态转移$x->y$相当于是建立一条$x$到$y$的边权为$1$的有向边,最小值相当于是$str[i-1]->str[i],(0<i<len(str))$的最短路,所以直接建图,邻接矩阵存,对每个情况跑一遍$floyd$算法即可。

AC代码:$(200ms)$

#include <bits/stdc++.h>
using namespace std;
int dp[15][15],len;
char str[2000005];
const int inf=0x3f3f3f3f;
int solve(int x,int y)
{
    memset(dp,inf,sizeof(dp));
    for(int i=0;i<10;++i)
        dp[i][(i+x)%10]=dp[i][(i+y)%10]=1;
    for(int k=0;k<10;++k)
        for(int i=0;i<10;++i)
            for(int j=0;j<10;++j)
                dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]);
    int ans=0;
    for(int i=1;i<len;++i)
    {
        if(dp[str[i-1]-‘0‘][str[i]-‘0‘]>=inf)
            return -1;
        ans+=dp[str[i-1]-‘0‘][str[i]-‘0‘]-1;
    }
    return ans;
}
int main()
{
    scanf("%s",str);
    len=strlen(str);
    for(int i=0;i<10;++i)
        for(int j=0;j<10;++j)
            printf("%d%c",solve(i,j),(j==9?‘\n‘:‘ ‘));
    return 0;
}

原文地址:https://www.cnblogs.com/Aya-Uchida/p/11330649.html

时间: 2024-08-02 18:44:01

codeforces1202B You Are Given a Decimal String... 记忆化搜索或Floyd最短路算法的相关文章

Count the string(记忆化搜索)

Count the string Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4899    Accepted Submission(s): 2313 题目连接 Problem Description It is well known that AekdyCoin is good at string problems as well

C语言记忆化搜索___Count the string(Hdu 3336)

Problem Description It is well known that AekdyCoin is good at string problems as well as number theory problems. When given a string s, we can write down all the non-empty prefixes of this string. For example: s: "abab" The prefixes are: "

UVA 10981 - String Morphing(记忆化搜索)

题目链接:10981 - String Morphing 题意:给定开始的字符串,要求根据表格变化成一个字符串,问变化的顺序(注意,不一定要最少步数) 思路:记忆化搜索,用map来存字符串的状态,一开始按最少步数去做TLE,其实只要找到一个符合的就可以了 代码: #include <stdio.h> #include <iostream> #include <string.h> #include <string> #include <map> u

UVA - 10559 Blocks 和 Vasya and Binary String CodeForces - 1107E (dp OR 记忆化搜索)

UVA - 10559 Blocks 题意:消消乐,每次连续相同的可以消除,分数加上长度的平方,问最多可以获得几分全部消完 题解: 区间dp + 记忆化搜索 dp[i][j][k] : (区间 [i,  j] 后面带上一段和 j 颜色相同的且长度为 k )的消消乐最大积分 1.消最后一段颜色和 j 颜色相同的 dp[i][j][k] <-- dp[i][j-1][0] + (k+1)^2 2.对于i <= l < j, 如果 l 和 j 的颜色相同, 那么可以把 [l+1, j-1]消掉

HDU 2476 String painter(记忆化搜索, DP)

题目大意: 给你两个串,有一个操作! 操作时可以把某个区间(L,R) 之间的所有字符变成同一个字符.现在给你两个串A,B要求最少的步骤把A串变成B串. 题目分析: 区间DP, 假如我们直接想把A变成B,那么我们DP区间的时候容易产生一个问题:假如我这个区间更新了,那么之前这个区间的子区间内DP出来的值就没用. 然后考虑到这里一直想不过去.最后看了看题解才知道. 我们可以先预处理一下怎么将一个空串变成B串需要的操作数. 这样我们就不用考虑子区间被覆盖的情况了. 如区间L,R 我们需要考虑的是点L是

HDU 1513 Palindrome:LCS(最长公共子序列)or 记忆化搜索

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1513 题意: 给你一个字符串s,你可以在s中的任意位置添加任意字符,问你将s变成一个回文串最少需要添加字符的个数. 题解1(LCS): 很神奇的做法. 先求s和s的反串的LCS,也就是原串中已经满足回文性质的字符个数. 然后要变成回文串的话,只需要为剩下的每个落单的字符,相应地插入一个和它相同的字符即可. 所以答案是:s.size()-LCS(s,rev(s)) 另外,求LCS时只会用到lcs[i-

uva 1076 - Password Suspects(AC自动机+记忆化搜索)

题目链接:uva 1076 - Password Suspects 题目大意:有一个长度为n的密码,存在m个子串,问说有多少种字符串满足,如果满足个数不大于42,按照字典序输出. 解题思路:根据子串构建AC自动机,然后记忆化搜索,dp[i][u][s]表示第i个字符,在u节点,匹配s个子串. #include <cstdio> #include <cstring> #include <queue> #include <string> #include <

poj 1579(动态规划初探之记忆化搜索)

Function Run Fun Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 17843   Accepted: 9112 Description We all love recursion! Don't we? Consider a three-parameter recursive function w(a, b, c): if a <= 0 or b <= 0 or c <= 0, then w(a, b

记忆化搜索,FatMouse and Cheese

1.从gird[0][0]出发,每次的方向搜索一下,每次步数搜索一下 for(i=0; i<4; i++) { for(j=1; j<=k; j++) { int tx=x+d[i][0]*j; int ty=y+d[i][1]*j; if(tx>=0&&tx<n&&ty>=0&&ty<n&&grid[x][y]<grid[tx][ty]) { int temp=memSearch(tx,ty); i