uva 116 - Unidirectional TSP(精心設計的測試數據)

題目

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

/*
*/


發佈了74 篇原創文章 · 獲贊 25 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章