UVA-116

题意:

给一个mn(m<=10n<=100)的整数矩阵,从第一列任何一个位置出发每次向右,右上或者右下走一格,要求经过的整数之和最小。整个矩阵是环形的,即第一行的上一行是最后一行,最后一行的下一行是第一行。输出路径上每一行的行号,要求字典序最小。

思路:

定义状态dp[i][j]为从第一列出发到第j列第i行的最小值是多少,转移方程上面已经给出,照着转移就行,难点在于字典序最小,因为我们定义的的dp方程是正向递推的,所以对于判断字典序最小有点麻烦,对于两个相等的结果,需要逆向找出他们的起点来判断字典序谁最小,在代码简洁程度上远不如lrj,但不失为一种思路。

代码:

#include <bits/stdc++.h>
using namespace std;
int mp[100][200],pre[100][200];
int ans[200];int n,m;
void Debug()
{
    printf("***********************************\n");
    for(int i = 1;i<=n;++i)
    {
        for(int j = 1;j<=m;++j)
            printf("%2d ",mp[i][j]);
        printf("\n");
    }
}
void check(int &a,int b,int &c,int j)
{
    if(mp[b][j-1]<mp[a][j-1])
    {
        a = b;
        c = mp[b][j-1];
    }
    else if(mp[b][j-1]==mp[a][j-1])
    {
        vector<int>t1(m+1),t2(m+1);
        int k = a;
        int i =j-1;
        while(i>=1)
        {
            t1[i] = k;
            k = pre[k][i];
            --i;
        }
        k = b;
        i = j-1;
        while(i>=1)
        {
            t2[i] = k;
            k = pre[k][i];
            --i;
        }
        for(int  i = 1;i<j;++i)
        {
            if(t2[i]!=t1[i])
            {
                if(t2[i]<t1[i])
                {
                     a = b;
                c = mp[b][j-1];
                }

                return ;
            }
        }
    }
    return ;
}
int main()
{
   //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i = 1;i<=n;++i)
        {
            for(int j = 1;j<=m;++j)
            {
                scanf("%d",&mp[i][j]);
                pre[i][j] = -1;
            }
        }
        if(m==1)
        {
            int mi = mp[1][1],id = 1;
            for(int i = 1;i<=n;++i)
            {
                if(mp[i][1]<mi)
                {
                    mi = mp[i][1];
                    id = i;
                }
            }
            printf("%d\n%d\n",id,mi);
            continue;
        }
        for(int i = 2;i<=m;++i)
        {
            for(int j = 1;j<=n;++j)
            {
                int tmp = j;
                --tmp;
                if(tmp==0)
                    tmp = n;
                int id = tmp,mi = mp[tmp][i-1];
              //  cout << "i = " << i << " " << " j = " << j << endl;
                //cout << id << " " << mi << endl;
                tmp = j,
                check(id,tmp,mi,i);
                tmp = j+1;
                if(tmp>n)
                    tmp = 1;
                check(id,tmp,mi,i);
                mp[j][i]+=mi;
                pre[j][i] = id;
            }
        }
        //Debug();
        for(int i =1;i<=m;++i)
            ans[i] = n;
        int mi = mp[1][m];
        for(int i =2;i<=n;++i)
            mi = min(mi,mp[i][m]);
        for(int i =1;i<=n;++i)
        {
            if(mp[i][m]==mi)
            {
                vector<int> t(m+1);
                int k = i,j= m;
                while(j>=1)
                {
                    t[j] =k;
                    //--j;
                    k = pre[k][j];
                    --j;
                }
                bool flag = false;
                for(int i = 1;i<=m;++i)
                {
                    if(t[i]!=ans[i])
                    {
                        if(t[i]<ans[i])
                        flag = true;
                        break;
                    }
                }
                if(flag)
                {
                    for(int i =1;i<=m;++i)
                        ans[i] = t[i];
                }
            }
        }
        printf("%d",ans[1]);
        for(int i  =2;i<=m;++i)
            printf(" %d",ans[i]);
        printf("\n");
        printf("%d\n",mi);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/baihualiaoluan/p/12349901.html
116