码迷,mamicode.com
首页 > 其他好文 > 详细

多米诺骨牌

时间:2019-08-20 22:25:13      阅读:87      评论:0      收藏:0      [点我收藏+]

标签:开始   最小   ring   log   绝对值最小   答案   mes   tail   www   

题目传送门

结合两篇题解:

1
2

有了我这篇博客。
主要思路是题解1。初始时先将所有骨牌翻转成上边的点数大,假设这时上下点数之差为\(tot\),此时翻转的骨牌数记为\(base\)。那么现在要再次翻转骨牌使得差值变小,假设第\(i\)张骨牌上下差值为\(k\),那么将这张骨牌翻转过来差值会减小\(2*k\)。明显最终差值会减到负值。当差值减到0时是最优答案。将减小的差值统一加上\(tot\),那么差值越接近\(tot\),答案越优。取所有差值减去\(tot\)的绝对值最小的一个便是答案。要注意减小的差值可能有0的情况(第10个点)。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int N = 1005;
int dp[N][N*6],w[N],v[N],n,tot,base,tot1,ansp,ans=2147483647;
bool vs[N][N*6];
int main()
{
    ansp=2147483647;
    int x,y;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&x,&y);
        tot1+=x-y;
        if(x>y)
        {
            v[i]=2*(x-y); w[i]=1;
            tot+=x-y;
        }
        if(y>x)
        {
            v[i]=2*(y-x); w[i]=-1;
            tot+=y-x;
            base++;
        }
    }
    for(int i=1;i<=n;i++)
     for(int j=0;j<=tot+tot;j++)
     {
        dp[i][j]=dp[i-1][j];
        vs[i][j]=vs[i-1][j];
        if(vs[i-1][j-v[i]]||j-v[i]==0)
        {
            if(!vs[i][j])
            {
                dp[i][j]=dp[i-1][j-v[i]]+w[i];
                vs[i][j]=1;
            }
            else dp[i][j]=min(dp[i][j],dp[i-1][j-v[i]]+w[i]);
        }
     }
    for(int i=0;i<=tot+tot;i++)
    if(vs[n][i])
    {
        if(abs(i-tot)==ans) ansp=min(ansp,dp[n][i]);
        if(abs(i-tot)<ans) ans=abs(i-tot),ansp=dp[n][i];
    }
    printf("%d\n",ansp+base);
    return 0;
} 
/*
2
3 2
2 2
*/

最开始的思路和第二篇博客里的思路一一样,但这种思路是不行的。加入当前枚举到\((i,j)\),有一个答案为\(a\),一个答案为\(-a\),无法判断在以后的转移中那个更优。
思路二值得借鉴,但是没写。

多米诺骨牌

标签:开始   最小   ring   log   绝对值最小   答案   mes   tail   www   

原文地址:https://www.cnblogs.com/karryW/p/11385708.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!