5248: [2018多省省队联测]一双木棋

容易写出暴力.
c++代码如下:

#include<bits/stdc++.h>
#define rep(i,x,y) for(register int i = x; i <= y; ++ i)
#define repd(i,x,y) for(register int i = x; i >= y; -- i)
using namespace std;
typedef long long ll;
template<typename T>inline void read(T&x)
{
    x = 0;char c;int sign = 1;
    do { c = getchar(); if(c == '-') sign = -1; }while(!isdigit(c));
    do { x = x * 10 + c - '0'; c = getchar(); }while(isdigit(c));
    x *= sign; 
}

const int N = 11,inf = 1e9+7,M = 1e6+50;
int n,m,a[N][N],b[N][N];
bool vis[N][N];

int dfs(int x,int y,bool k)
{
    if(x == n && y == m) return k ? -b[x][y] : a[x][y];
    int ans = k ? -inf : inf;
    vis[x][y] = 1;
    rep(i,1,n) rep(j,1,m)
        if(vis[i - 1][j] && vis[i][j - 1] && !vis[i][j]){
            if(k)
            {
                ans = max(ans,dfs(i,j,k^1) - b[x][y]);
            }
            else ans = min(ans,dfs(i,j,k^1) + a[x][y]);
    }

    vis[x][y] = 0;
    return ans;
}

int main()
{
    read(n); read(m);
    rep(i,1,n) rep(j,1,m)
        read(a[i][j]);
    rep(i,1,n) rep(j,1,m)
        read(b[i][j]);

    rep(i,0,m) vis[0][i] = 1;
    rep(i,0,n) vis[i][0] = 1;
    cout << dfs(1,1,0) << endl;

    return 0;
}

上述代码50分.
考虑如何优化
发现其实每一层当前能选的都是固定的.
那么考虑状压来表示出每一层的状态.
因为m最大为10,根据题意显然总变化不会超过10
用1表示向左边移动,0表示该层结束
那么可以用f[i][j]表示第一层从i开始,接下来状态为j
比如i = 5,j = 111010(2进制)
表示第一层为5 ,第二层为5,第三层为4,第五层为1,接下来的层均为1.
那么这样表示发现状态一定不会超过2^20
然后考虑转移即可。
c++代码如下:

#include<bits/stdc++.h>
#define rep(i,x,y) for(register int i = x; i <= y; ++ i)
#define repd(i,x,y) for(register int i = x; i >= y; -- i)
using namespace std;
typedef long long ll;
template<typename T>inline void read(T&x)
{
    x = 0;char c;int sign = 1;
    do { c = getchar(); if(c == '-') sign = -1; }while(!isdigit(c));
    do { x = x * 10 + c - '0'; c = getchar(); }while(isdigit(c));
    x *= sign; 
}

const int N = 21,inf = 0x3f3f3f3f,M = 1e6+50;
int n,m,a[N][N],b[N][N],f[N][1<<N];

int solve(int x)
{
    int p[50],len = 0;
    while(x)
    {
        p[++len] = x&1;
        x >>= 1;
    }
    repd(i,len,1) printf("%d",p[i]);
    puts("");
}

int dfs(int x,int s,bool k)
{
    if(f[x][s] != inf) return f[x][s];
    if(x == m && !s) return f[x][s] = 0;
    f[x][s] = k ? inf : -inf;

    int p[N],y = 0,S = s,len = 1;
    memset(p,0,sizeof p); p[1] = x;
    while(S)
    {
        if(!(S&1)) p[++len] = x - y;
        else ++y;
        S >>= 1;
    }
    while(++len <= n) p[len] = x - y;

    if(x != m)
        if(!k) f[x][s] = max(dfs(x + 1,s<<1|1,k^1) + a[1][x + 1],f[x][s]);
        else f[x][s] = min(dfs(x + 1,s<<1|1,k^1) - b[1][x + 1],f[x][s]);

    rep(i,2,n)
        if(p[i] != p[i-1]){
            y = 0;
            ++p[i];
            repd(j,n,2)
            {
                int k = p[j - 1] - p[j];
                while(k--) y = y<<1|1;
                y <<= 1;
            }y>>=1;
            if(!k) f[x][s] = max(dfs(x,y,k^1) + a[i][p[i]],f[x][s]);
            else f[x][s] = min(dfs(x,y,k^1) - b[i][p[i]],f[x][s]);
            --p[i];

    }

    return f[x][s];
}

int main()
{
    memset(f,0x3f,sizeof f);
    read(n); read(m);
    rep(i,1,n) rep(j,1,m)
        read(a[i][j]);
    rep(i,1,n) rep(j,1,m)
        read(b[i][j]);

    cout << dfs(1,1,1) + a[1][1] << endl;

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值