题目大意是说,一个数字矩阵,从第1列到最后一列,一步可以往右走、右上走、右下走。路权为这条路径上的数字之和。输出最小路权及字典序最小的路径。
这题的一大亮点是,如果采用遍历每条路径从而获得字典序最小的路径的话,必然会超时;或者要加上剪枝才能通过检测,但是我没有找到强有力的剪枝。求神牛指点。
正确的做法是从后往前转移状态,假如当前往右、右上、右下都一样最优,则选择右上,每一步都这样做,必定是字典序最小的路径。记录在当前位置做出的选择。
AC:
#include<cstdio>
#include<cstring>
#include<math.h>
#include<stdlib.h>
#include<algorithm>
#include<ctime>
#include<iostream>
#define INF 1<<30
using namespace std;
const int maxm=10+10;
const int maxn=100+10;
typedef int G[maxm][maxn];
G a,way,f;
int main()
{
#ifndef ONLINE_JUDGE
freopen("in1.txt","r",stdin);
#endif
int i,j;
int m,n;
while(scanf("%d%d",&m,&n)==2)
{
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
scanf("%d",&a[i][j]);//mistook:a[m][n]
for(i=1;i<=m;i++) f[i][n]=a[i][n];
for(j=n-1;j>=1;j--)
for(i=1;i<=m;i++)
{
int &ans=f[i][j];
ans=INF;
for(int k=-1;k<=1;k++)
{
int p=(i+k-1+m)%m+1;
if(f[p][j+1]<ans)
{
ans=f[p][j+1];
way[i][j]=p;
}else if(f[p][j+1]==ans && p<way[i][j])
{
way[i][j]=p;
}
}
ans+=a[i][j];
}
int mm,ans=INF;
for(i=1;i<=m;i++)
if(f[i][1]<ans)
{
ans=f[i][1];
mm=i;
}
printf("%d",mm);
int x=mm,y=1;
while(y<n)
{
x=way[x][y];
printf(" %d",x);
y++;
}
printf("\n%d\n",ans);
}
//printf("%.2lf\n",(double)clock()/CLOCKS_PER_SEC);
return 0;
}
/*
*/
非正确程序,卡时返回,不能通过,数据太强:
#include<cstdio>
#include<cstring>
#include<math.h>
#include<stdlib.h>
#include<algorithm>
#include<ctime>
#include<iostream>
#define INF 1<<30
using namespace std;
const int maxn=100+10;
const int maxm=10+10;
const int maxTimes=10000;
bool vis[maxm][maxn];
int f[maxm][maxn];
int a[maxm][maxn];
int m,n;
int dp(int i,int j)
{
int &ans=f[i][j];
if(vis[i][j]) return ans;
vis[i][j]=true;
if(j==1) return ans=a[i][j];
ans=INF;
for(int k=-1;k<=1;k++)
ans=min(ans,dp((i+k-1+m)%m+1,j-1));
ans+=a[i][j];
return ans;
}
int bestPath[maxn],path[maxn];
bool first;
int times;
bool findPath(int i,int j)
{
int k;
if(j==0)
{
if(first)
{
memcpy(bestPath,path,sizeof(bestPath));
first=false;
}else
{
for(k=1;k<=n;k++)
if(path[k]!=bestPath[k])
break;
if(path[k]<bestPath[k])
memcpy(bestPath,path,sizeof(bestPath));
}
if(++times>maxTimes) return true;
return false;
}
path[j]=i;
for(k=-1;k<=1;k++)
{
int p=(i+k-1+m)%m+1;
if(f[i][j]==f[p][j-1]+a[i][j])
{
if(findPath(p,j-1)) return true;
}
}
return false;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
int i,j;
while(scanf("%d%d",&m,&n)==2)
{
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
scanf("%d",&a[i][j]);
memset(vis,0,sizeof(vis));
memset(f,0,sizeof(f));
for(i=1;i<=m;i++) dp(i,n);
int A[n],An;
int ans=INF;
for(i=1;i<=m;i++)
if(f[i][n]<=ans)
{
if(f[i][n]<ans)
{
An=0;
ans=f[i][n];
}
A[An++]=i;
}
first=true;
for(i=0;i<An;i++)
{
times=0;
findPath(A[i],n);
}
printf("%d",bestPath[1]);
for(i=2;i<=n;i++) printf(" %d",bestPath[i]);
printf("\n%d\n",ans);
}
//printf("%.2lf\n",(double)clock()/CLOCKS_PER_SEC);
return 0;
}
/*
*/