D. Nastya and Scoreboard ( DFS暴力 + 优化 )

Codeforces 1341-D ( DFS暴力 + 优化 )

题目链接:https://codeforc.es/contest/1341/problem/D

题意:有一块电子显示屏,0~9的显示如图。给n块显示屏,和它们现在的状态( 不一定是某个数字 ),问能否再打开正好k个灯管,让n块显示屏显示出一个数,要求这个数尽可能大。

D. Nastya and Scoreboard ( DFS暴力 + 优化 )_第1张图片

D. Nastya and Scoreboard ( DFS暴力 + 优化 )_第2张图片

输入: 第一行输入n和k,接下来n行每行输入长度为7的01字符串,1表示亮着,0表示没亮。

输出:打开正好k根灯管,输出n个显示屏获取的最大数字。

input

2 5
0010010
0010010

output

97

思路:尝试暴力求解,枚举第一个是否可以是9,是否可以是8...., 枚举第二个是否可以是9,是否可以是8...

用dfs可以很容易写出来,但复杂度有点高,因该是O( 10^{n} ),但考虑到不是每一个状态都可以转换成10个数,估算底数比较小。但n=2000,底数是2的2000次方也绝对T了。( 比赛时T7了 )

现在观察一下这个dfs函数,void dfs( int pos, int sum ), 传入值有两个,一个是枚举的第几块显示屏,一个是枚举到当前点亮的灯管数。两个取值都是1~2000,所以整个dfs的情况也只有2000*2000=4000000种,我们只需要开个数组记录每种状态的结果,4e6的复杂度就可以接受了。

有点类似于数位dp,数位dp也是感觉复杂度很高,但其实大量的状态是重复的,我们只需要用数组记录每个状态的结果就避免了每次都要重新算的复杂度。

代码:

#include
#define int long long

using namespace std;

const int maxn = 2e5+10;
string s[2003];
string name[10];
int ans[2005], flag, n, k;
int dp[2005][2005];

void dfs( int pos, int sum )
{
    if ( flag==1 || sum<0 ) return ;
    if ( pos>=n ) {
        if ( sum==0 ) {
            flag = 1;
            for ( int i=0; i=0; i-- ) {
        int isp = 1;
        int cnt = 0;
        for ( int j=0; j<7; j++ ) {
            if ( name[i][j]==s[pos][j] ) {

            }
            else if ( name[i][j]=='1' && s[pos][j]=='0' ) {
                cnt ++;
            }
            else {
                isp = 0;
                break;
            }
        }
        if ( isp==0 ) continue ;
        ans[pos] = i;
        dfs(pos+1,sum-cnt);
    }
    if ( flag==0 ) dp[pos][sum]=-1;  // 最重要的优化2
}

signed main()
{
    name[0]="1110111", name[1]="0010010", name[2]="1011101", name[3]="1011011", name[4]="0111010", name[5]="1101011",
    name[6]="1101111", name[7]="1010010", name[8]="1111111", name[9]="1111011";
    cin >> n >> k;
    for ( int i=0; i>s[i];
    }
    flag=0;
    dfs(0,k);
    if ( flag==0 ) cout << "-1" << endl;

    return 0;
}

 

你可能感兴趣的:(搜索补题)