uva 11464 Even Parity 递推

来源:互联网 发布:js explode 编辑:程序博客网 时间:2024/06/06 02:21

题目链接:

https://uva.onlinejudge.org/external/114/11464.pdf


首先可以知道每个数字,可以改变或不改变(当然 依题意 ,是0才能够改变)

这样暴力枚举会超时。

那么既然暴力枚举不行,就证明有非暴力的解决方法:

1. 贪心或规律,(直接找到解题策略)认为的找出改变方法,此策略对所有情况均适用。

2.找出部分规律 ,定下解答的一部分 ,然后计算其余可变化的部分,枚举或有效利用各种算法,减少时间复杂度。

两者均比直接暴力时间要少。

对于一个题目,首先有直接求解法,比如说先直接分步,或是先直接分类,然后加以计算。

                             还有间接求解法,比如说我想知道f[n]的值,却不知道怎样直接求出 f[n], 但我知道f[1]的值,也知道f[i]怎么推出f[i+1],那么我可以从f[1]步步递推,

                            直到求出f[n]。

反观自己,过去对于递推的理解实在很狭隘,不知道递推的好处,也不知道怎么用递推:


首先,分析一个问题,一定要充分抓住已知条件,一个题目里面变化的东西有很多,但是也有不变的东西,

 先要确定不变的是什么,(排序规则 ,选取规则 ,时间长短...)

当初想这个问题,就是使劲去找到底什么不变?选择点的方法?还是有什么数量规律?翻来覆去就是弄不出来。

因为,如果能找出定的信息或规律,一定是要有用的,可以利用求出答案的。


第二,

递推找到起点很重要,知道了dp[0]=1(计数DP),才可能推出后面的,而且这个dp[0]=1是个起点,什么不选的情况就是1种。

因为平时递推的起点很显然,没有注意过,而这个题很隐蔽,所以让人想不到递推。


第三,

递推关系很重要,

这个题的条件其实可以转化为递推关系:   假如某个点的上、左、右已经确定了,那么它下个点就确定了。

(这就是递推关系)

证明我们善于要分析出隐蔽的递推关系

这个题也是,看不出有递推关系,压根想不到递推。 (这个递推关系就是个定的,不变的规律


对于此题,充分利用递推关系,确定递推起点,则可得解。

这个题的解法:首先枚举第一行的情况,然后根据第一行,可以推出第二行,之后根据第二行推出第三行,(证明递推的顺序很重要

直到推出第n行。

属于解法2.


综上:对于一个问题,先要找到问题的大致方向,是暴力枚举,还是人为想出特定解法,还是充分利用 已知条件(还不足以求出答案) 再加上高效算法。

          如果想用递推解决问题,那么先要确立递推关系(状态转移方程),找到隐蔽的递推起点,然后决定递推顺序,

(之所以这样,因为很多题目这三者实在太显然,让我们忽略了它们的重要性)。

int a[maxn][maxn];int b[maxn][maxn];int n,ans;bool ok;int kase;int dir[4][2]={{-1,0},{0,-1},{0,+1},{+1,0} };int f(int y,int x){    int ans=0;    for(int i=0;i<3;i++)    {        int ty=y+dir[i][0];        int tx=x+dir[i][1];        ans+=b[ty][tx];    }    return ans;}int f2(int y,int x){    int ans=0;    for(int i=0;i<4;i++)    {        int ty=y+dir[i][0];        int tx=x+dir[i][1];        ans+=b[ty][tx];    }    return ans;}int check( ){    int cnt=0;    for(int i=2;i<=n;i++)    {        for(int j=1;j<=n;j++)        {            int tmp=f(i-1,j);            if( (tmp%2) !=a[i][j])            {                if(a[i][j]==1)  {cnt=-1;return cnt;}                cnt++;                b[i][j]=1;            }            else            {                b[i][j]=a[i][j];            }        }    }         /*我担心这样推出后,最后一排的没有验证是否符合,         所以单独拿出来验证一遍,书中没有验证,我还没想清为什么*/    for(int i=1;i<=n;i++)    {            if(f2(n,i)%2)  {cnt=-1;break;}    }    return cnt;}void dfs(int step,int num){    if(step==n+1)    {        int tmp;        if( ( tmp=check(  ) )!=-1  )        {              ans=min(ans,tmp+num);        }        return;    }  if(!a[1][step])  {      b[1][step]=1;      dfs(step+1,num+1);  }    b[1][step]=a[1][step];    dfs(step+1,num);}int main(){    int T;kase=0;    scanf("%d",&T);    while(T--)    {        scanf("%d",&n);        for(int i=1;i<=n;i++)        {            for(int j=1;j<=n;j++)                scanf("%d",&a[i][j]);        }        memset(b,0,sizeof b);   //这句话掉了就错,虽然我认为不影响,但要注意。        ans=INF;         dfs(1,0);       if(ans==INF) ans=-1;        printf("Case %d: %d\n",++kase,ans);    }    return 0;}


头文件:

#include<cstdio>#include<string>#include<cstring>#include<iostream>#include<cmath>#include<algorithm>#include<climits>#include<queue>#include<vector>#include<map>#include<sstream>#include<set>#include<stack>#include<utility>#pragma comment(linker, "/STACK:102400000,102400000")#define PI 3.1415926535897932384626#define eps 1e-10#define sqr(x) ((x)*(x))#define FOR0(i,n)  for(int i=0 ;i<(n) ;i++)#define FOR1(i,n)  for(int i=1 ;i<=(n) ;i++)#define FORD(i,n)  for(int i=(n) ;i>=0 ;i--)#define  lson   num<<1,le,mid#define rson    num<<1|1,mid+1,ri#define MID   int mid=(le+ri)>>1#define zero(x)((x>0? x:-x)<1e-15)#define mk    make_pair#define _f     first#define _s     secondusing namespace std;const int INF =0x3f3f3f3f;const int maxn= 20   ;//const int maxm=    ;//const int INF=    ;typedef long long ll;//const ll inf =1000000000000000;//1e15;//ifstream fin("input.txt");//ofstream fout("output.txt");//fin.close();//fout.close();//freopen("a.in","r",stdin);//freopen("a.out","w",stdout);//by yskysker123




0 0
原创粉丝点击