您的位置:首页 > 其它

uva 116 - Unidirectional TSP(精心设计的测试数据)

2012-10-21 16:20 507 查看
题目

题目大意是说,一个数字矩阵,从第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]

    for(i=1;i<=m;i++) f[i]
=a[i]
;
    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
,An;
    int ans=INF;
    for(i=1;i<=m;i++) 
      if(f[i]
<=ans)
      {
      	if(f[i]
<ans) 
      	{
	      	An=0;
	      	ans=f[i]
;
	      }
      	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;
}

/*
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: