规律,模拟,贪心(Travelling Salesman Problem,HDU 5402)

13 篇文章 0 订阅
5 篇文章 0 订阅

显然行列有一个是奇数就可以全部走完。这种情况直接模拟就好。

否则的话,一定会有一个格子走不到。

多试几种情况就可以发现这个规律。

证明的话:http://blog.csdn.net/queuelovestack/article/details/47756605

就是对整个棋盘进行黑白二染色,如果行列相加为偶数,就染成黑色,否则染成白色。我们的路径一定是黑白相间。

当行列皆为偶数的时候我们可以发现矛盾。

此时(1,1)是黑色,(n,m)也是黑色。因为路径黑白相间,所以经过的白色格子一定比黑色格子少一个。而整个棋盘中黑白格子的个数是相等的,所以至少有1个白色格子是走不到的。

比赛时不一定能想到严格证明,但若能发现规律,并且有一定把握也是可以的。

至于该如何模拟,看到了网上有很简单的办法,就是随便绕绕就绕过去了,我的模拟就麻烦很多了。

如果可以,尽量想出一些简单的模拟办法,当然能想到自己的办法是好事,但这可能会给编程带来一些麻烦。

希望自己在找到线索之后可以进一步地把它想清楚,从而找到更简单的规律,然后再开始编程。


代码

#include<stdio.h>
#include<vector>
using namespace std;
const int maxn = 110;

int n,m;
int MAP[maxn][maxn];
int mr,mc;
vector<char>vec;
int ans;
int vis[maxn][maxn];

void read()
{
    ans=0;
    vec.clear();
    mr=mc=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            vis[i][j]=0;
            scanf("%d",&MAP[i][j]);
            if(!(i==1&&j==1)&&!(i==n&&j==m)&&((i+j)&1)&&MAP[mr][mc]>MAP[i][j])
            {
                mr=i;
                mc=j;
            }
        }
}

bool ok(int r,int c)
{
    return 1<=r&&r<=n&&1<=c&&c<=m&&!(r==mr&&c==mc)&&!vis[r][c];
}

int change(int r,int c,int t)
{
    if(t==0)
    {
        if(c==m) return 1;
        for(int i=1;i<=n;i++)
            if(ok(i,c+1)&&!vis[i][c+1]) return 0;
        return 1;
    }
    if(t==1)
    {
        if(c==1) return n-r<=m-c?2:0;
        for(int i=1;i<=n;i++)
            if(ok(i,c-1)&&!vis[i][c-1]) return 1;
        return n-r<=m-c?2:0;
    }
    if(t==2)
    {
        if(r==n) return 3;
        for(int i=1;i<=m;i++)
            if(ok(r+1,i)&&!vis[r+1][i]) return 2;
        return 3;
    }
    if(t==3)
    {
        if(r==1) return n-r<m-c?2:0;;
        for(int i=1;i<=m;i++)
            if(ok(r-1,i)&&!vis[r-1][i]) return 3;
        return n-r<m-c?2:0;
    }
    return 0;
}

void dfs(int r,int c,int t)
{
    ans+=MAP[r][c];
    vis[r][c]=1;
    if(r==n&&c==m) return;
    t=change(r,c,t);
    if(t==0)
    {
        if(ok(r-1,c))
        {
            vec.push_back('U');
            dfs(r-1,c,t);
        }
        else if(ok(r,c+1))
        {
            vec.push_back('R');
            dfs(r,c+1,t);
        }
        else if(ok(r+1,c))
        {
            vec.push_back('D');
            dfs(r+1,c,t);
        }
        return;
    }
    else if(t==1)
    {
        if(ok(r-1,c))
        {
            vec.push_back('U');
            dfs(r-1,c,t);
        }
        else if(ok(r,c-1))
        {
            vec.push_back('L');
            dfs(r,c-1,t);
        }
        else if(ok(r+1,c))
        {
            vec.push_back('D');
            dfs(r+1,c,t);
        }
        return;
    }
    else if(t==2)
    {
        if(ok(r,c-1))
        {
            vec.push_back('L');
            dfs(r,c-1,t);
        }
        else if(ok(r+1,c))
        {
            vec.push_back('D');
            dfs(r+1,c,t);
        }
        else if(ok(r,c+1))
        {
            vec.push_back('R');
            dfs(r,c+1,t);
        }
        return;
    }
    else if(t==3)
    {
        if(ok(r,c-1))
        {
            vec.push_back('L');
            dfs(r,c-1,t);
        }
        else if(ok(r-1,c))
        {
            vec.push_back('U');
            dfs(r-1,c,t);
        }
        else if(ok(r,c+1))
        {
            vec.push_back('R');
            dfs(r,c+1,t);
        }
        return;
    }
}

void handle()
{
    if(n>=m) dfs(1,1,0);
    else dfs(1,1,2);
}

void solve()
{
    read();
    if((n&1)==0&&(m&1)==0);
    else mr=mc=0;
    handle();
    printf("%d\n",ans);
    for(int i=0;i<(int)vec.size();i++)
        printf("%c",vec[i]);
    puts("");
}

int main()
{
    MAP[0][0]=10010;
    while(~scanf("%d %d",&n,&m)) solve();
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值