BNU 11993 Soccer Teams (01背包变形+数位dp)

题意:

给出9个数分别表示有a[i]数字i,现在这些数字都要用上,但是可以附加任何个0。问能被11整数的数的最小位数是多少。

题解:

01背包的变形有点像数位dp对位进行操作。dp[i][j]表示去了i位并且这些位上的和%11位j,dp[i][j]计算出的是奇数位上数的和为j的情况,之后枚举奇数位,得出偶数位,进行比较取得位数的最小值。


#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
const int oo=0x3f3f3f3f;
const ll OO=1LL<<61;
const ll MOD= 1000000007;
const int maxn=105;
const int maxm=1005;
int a[10];
int dp[205][12];///去了i位并且奇数位上的和模以11为j是否可达  i和j都作为背包的容量

int main()
{
    int T,sum,cnt;
    scanf("%d",&T);
    while(T--)
    {
        sum=cnt=0;
        for(int i=1;i<=9;i++)
        {
            scanf("%d",&a[i]);
            cnt+=a[i];
            sum+=a[i]*i;
        }
        memset(dp,0,sizeof dp);
        ///01背包枚举物品
        dp[0][0]=1;
        for(int dig=1;dig<=9;dig++)
        {
            for(int t=1;t<=a[dig];t++)
            {
                for(int i=maxn-1;i>=0;i--)
                {
                    for(int j=0;j<11;j++)
                    {
                        if(dp[i][j])
                            dp[i+1][(j+dig)%11]=1;
                    }
                }
            }
        }
        int add=10000;///另外偶数位
        for(int i=1;i<=cnt;i++)///枚举奇数位
        {
            for(int j=0;j<11;j++)
            if(dp[i][j])
            {
                if((sum%11-j-j)%11!=0)continue;
                int lt=cnt-i;
                if(i==lt)
                {
                    add=0;
                    break;
                }
                else
                {
                    add=min(add,abs(i-lt)-1);
                }
            }
        }
        if(add==10000)add=-cnt-1;
        printf("%d\n",cnt+add);
    }
    return 0;
}
/***
200
100 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 1
*/



你可能感兴趣的:(BNU 11993 Soccer Teams (01背包变形+数位dp))