題目大意是說,一個數字矩陣,從第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;
}
/*
*/