Uva 116 - Unidirectional TSP

 3Y today

( 10Y before )

终于搞定了!!!

这玩意好烦

估计是之前字典序没弄好==

dp的构建就是分段图遍历的做法

然后解释一下ok

用于字典序输出

反着找出一切可能被遍历的点

然后正向输出

没输出一个值

把所有不可能的点排除( ok清零 )

就好了

终于搞定了!!!!!

#include<stdio.h>
#define LL long long
LL map[20][110];
LL dp[20][110];
LL m,n;
LL min3(LL a,LL b,LL c){
	LL res=a;
	if(b<res)res=b;
	if(c<res)res=c;
	return res;
	}
int main(){
	while(scanf("%lld%lld",&n,&m)!=EOF){		//n行m列 
		int i,j;
		for(i=1;i<=n;i++)for(j=1;j<=m;j++)scanf("%lld",&map[i][j]);
		for(i=1;i<=m;i++){
			for(j=1;j<=n;j++){
				dp[j][i]=map[j][i];
				if(i!=1){
					int x,y;
					x=j+1;if(x==n+1)x=1;
					y=j-1;if(y==0)y=n;
					dp[j][i]+=min3(dp[x][i-1],dp[j][i-1],dp[y][i-1]);
					}
				}
			}
	/*	for(i=1;i<=n;i++){
			for(j=1;j<=m;j++)printf("%d ",dp[i][j]);
			printf("\n");
			}*/
		LL res=dp[n][m],pr=n;
		for(i=1;i<=n;i++)if(res>dp[i][m])res=dp[i][m],pr=i;
		bool ok[20][110];
		for(i=1;i<=n;i++)for(j=1;j<=m;j++)ok[i][j]=0;
		for(j=m;j>=1;j--){
			for(i=1;i<=n;i++){
				if(j==m){
					if(dp[i][j]==res)ok[i][j]=1;
					}
				else {
					int k;
					for(k=1;k<=n;k++){
						if(ok[k][j+1]){
							LL aim=dp[k][j+1]-map[k][j+1];
							int x,y;
							x=k+1;if(x==n+1)x=1;
							y=k-1;if(y==0)y=n;
							if(dp[x][j]==aim)ok[x][j]=1;
							if(dp[k][j]==aim)ok[k][j]=1;
							if(dp[y][j]==aim)ok[y][j]=1;
							}
						}
					}
				}
			}
		for(j=1;j<=m;j++){
			for(i=1;i<=n;i++){
				if(ok[i][j]){
					if(j!=1)printf(" ");
					printf("%d",i);
					int k;
					int x,y;
						x=i+1;if(x==n+1)x=1;
						y=i-1;if(y==0)y=n;
					for(k=1;k<=n;k++){
						if(k==i||k==x||k==y){
							if(dp[k][j+1]-map[k][j+1]!=dp[i][j])ok[k][j+1]=0;
							}
						else ok[k][j+1]=0;
						}
					break;
					}
				}
			}
		printf("\n%lld\n",res);
		}
	return 0;
	} 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值