2017暑训摸底(xdoj1045,xdoj1173,xdoj1007,xdoj1038)

由于时间没赶上摸底,只能跟一波新增的dp摸底,感觉难度一般般,可能有段时间内没做题的缘故吧

暑训就要开始了呢

 

A 黑白棋

 

思路:一上来就是个博弈搜索

根据上一状态与这一状态必胜必败态的转换来判断先手的情况

dfs搜索所有前项状态,若均为必败态,则该状态为必胜态,否则为必败态

 

 

/*
Author:Owen_Q
*/

#include 

using namespace std;

int a[5][5];

int dfs(int x,int y)
{
    int next[2][4]={{0,0,1,-1},{1,-1,0,0}};
    int x1,y1,i,p=1;
    for(i=0;i<4&&p==1;i++)
    {
        x1=x+next[0][i];
        y1=y+next[1][i];
        if(x1>=0&&y1>=0&&x1<5&&y1<5&&a[x1][y1]==0)
        {
            a[x1][y1]=1;
            p=(dfs(x1,y1)+1)%2;
            a[x1][y1]=0;
        }
    }
    return p;
}

int main()
{
    int i,j,t;
    scanf("%d",&t);
    while(t--)
    {
        for(i=0;i<5;i++)
        {
            for(j=0;j<5;j++)
            {
                scanf("%1d",&a[i][j]);
            }
        }
        int p=0;
        for(i=0;i<5&&p==0;i++)
        {
            for(j=0;j<5&&p==0;j++)
            {
                if(a[i][j]==0)
                {
                    a[i][j]=1;
                    p=dfs(i,j);
                    a[i][j]=0;
                }
            }
        }
        if(p==0)
            printf("lose\n");
        else
            printf("win\n");
    }
    return 0;
}

 

 

 

 

 

 

B The most orz man

思路:sg值打表找规律

sg值:mex函数为下一状态的sg值,则该状态sg值为最小不属于mex的非负整数

这是个很巧妙的方法,成功利用数学方式构造了必胜必败态模型,通过计算实现结果的模拟

最终发现3的整数倍为必胜态,成功ac

 

 

/*
Author:Owen_Q
*/

#include 

using namespace std;
/*
const int maxn = 10010;

int sg[maxn];

void getSG(int a[],int n)//a为可能走法,n为所求sg数量
{
	int i,j;
	int temp[maxn];//存储前项sg值,用于求mex
	memset(sg,0,sizeof(sg));
	for(i=0;i=0;j++)//j为可走步数
		{
			if(i

 

 

 

D 易碎的鸟蛋

 

思路:典型的dp,以两个题设变量鸡蛋数n和楼层数m作为状态变量,以所求结果最少实验次数作为dp值,枚举投放鸡蛋的试验楼层

可得到两种情况,分为鸡蛋破碎和未破碎,于是一分为二

若鸡蛋破碎,则继续试验较低楼层,但可用鸡蛋数减一

若鸡蛋未破,则将上层楼层提取出来,成为研究楼高仅为上层楼层的子问题

两种情况中较高的试验次数作为该状态的dp值,枚举结果中取最低值进行转移

转移方程为dp[i][j]=min((max(dp[i-1][k-1],dp[i][j-k])+1),dp[i][j])

 

 

/*
Author:Owen_Q
*/

#include 

using namespace std;

const int maxn = 1e3+10;

int dp[maxn][maxn];

int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int j=0;j<=1000;j++)
        {
            dp[0][j]=0;
            dp[1][j]=j;
            dp[j][0]=0;
            dp[j][1]=1;
        }
        for(int i=2;i<=n;i++)
        {
            for(int j=2;j<=m;j++)
            {
                dp[i][j]=dp[i-1][j];
                for(int k=1;k<=j;k++)
                {
                    dp[i][j]=min((max(dp[i-1][k-1],dp[i][j-k])+1),dp[i][j]);
                }
            }
        }
        printf("%d\n",dp[n][m]);
    }
    return 0;
}

 

 

 

 

 

最终摸底的结果还是可以接受的,全场第三,d题一开始总想着二分找最优状态,后来发现不足10的数据量完全可以枚举,或许利用计算机才是acm正确的姿势吧

 

dp专题,怎么能没有状压呢,上次的c题就是一个典型的状压

C 裁玻璃

思路:按层转移,每层的状态只与其上一层状态有关,由于每层的列数很少,完全可以考虑用二进制数存储状态,状态压缩。特殊考虑无法放玻璃的位置,对于本层将其考虑为未放置,对于下层,将其考虑为已放置。

关键对于不可能成立的情况,可以直接将其赋值为-1e9,避免其被挑选到,每次筛选出满足的最大值作为转移结果。

最后,就是注意第一层初始条件需要单独考虑,就ok了

 

/*
Author:Owen_Q
*/

#include 

using namespace std;

const int maxn = 2000;

int row,n,t;

int dp[maxn][12];
bool good[12][12];


void cal(int k,int state)
{
    int add = 0;
    int realstate = state;
    for(int i=0;idp[state][k]))
        {
            dp[state][k] = dp[s][k-1]+add;
        }
    }
    return ;
}

int main()
{
    //cout << (1<<10) << endl;
    while(scanf("%d",&t)!=EOF)
    {
        while(t--)
        {
            scanf("%d%d",&row,&n);
            memset(dp,0,sizeof(dp));
            memset(good,true,sizeof(good));
            for(int i=1;i<=row;i++)
            {

                for(int j=1;j<=n;j++)
                {
                    int temp;
                    scanf("%d",&temp);
                    if(temp == 0)
                    {
                        good[i][j] = false;
                    }
                }
            }
            for(int i=1;i<=row;i++)
            {

                for(int s=0;s<=((1<maxblock)
                {
                    maxblock = dp[s][row];
                }
            }
            printf("%d\n",maxblock);
            //cout << ((1<<3)|(1<<2)|(1<<1)|(1<<0)) <<"*"<=0)
                {
                    cout << s << "**" << dp[s][1] << endl;
                }
            }*/
        }
    }
    return 0;
}

 

 

 

 

 

你可能感兴趣的:(dp,xdoj,搜索)