hdu 4281 DP(多旅行商)

第一个问题:

先枚举出所有可能的组合,然后剩下的就是01背包了。。。。

第二个问题:多旅行商问题

可以先求单个的旅行商,然后再合成多个的

说实话第一次见到旅行商问题。。。。还是个多旅行商问题。。。。

np[i]表示 经过i这个状态中的点后回到0点的最小时间

cost[j][i]表示经过i中的状态的点后最后经过的是点j

 

然后求出单个的之后,从0开始dp上去,每次求得都是i状态下的最小时间

 

AC代码如下:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;

#define MAX 0x3f3f3f3f

typedef struct{
	double x, y;
}Point;

int N, M;
Point p[20];
int weight[20];
int dp[1<<16];
int dis[20][20];
int cost[16][1<<16];
int np[1<<16];
bool oki[1<<16];
int maxweight;
int statu[1<<16], tot;

bool ok( int s ){
	int sum = 0;
	for( int i = 0; i < N; i++ ){
		if( s & ( 1 << i ) ){
			sum += weight[i];
		}
	}
	if( sum <= M ){
		return true;
	}else{
		return false;
	}
}

void initial(){

	memset( dis, 0, sizeof( dis ) );
	for( int i = 0; i < N; i++ ){
		for( int j = i + 1; j < N; j++ ){
			double a = p[i].x - p[j].x;
			double b = p[j].y - p[i].y;
			dis[i][j] = dis[j][i] = ceil( sqrt( a * a + b * b ));
		}
	}

	tot = 0;
	for( int i = 0; i < ( 1 << N ); i++ ){
		oki[i] = ok(i);
		if( oki[i] ){
			statu[tot++] = i;
		}
	}

}

int solve_first(){
	memset( dp, 0x3f, sizeof( dp ) );
	dp[0] = 0;
	for( int i = 1; i < ( 1 << N ); i++ ){
		for( int j = 0; j < tot; j++ ){
			if( ( i | statu[j] ) == i ){
				dp[i] = min( dp[i], dp[i-statu[j]] + 1 );
			}
		}
	}
	return dp[(1<<N)-1] == MAX ? -1 : dp[(1<<N)-1];
}

int solve_second(){
	
	memset( np, 0x3f, sizeof( np ) );
	memset( cost, 0x3f, sizeof( cost ) );
	cost[0][1] = 0;

	for( int i = 1; i < ( 1 << N ); i++ ){
		if( !oki[i] ){
			continue;
		}
		for( int j = 0; j < N; j++ ){
			if( i & ( 1 << j ) ){
				np[i] = min( np[i], cost[j][i] + dis[j][0] );
				for( int k = 0; k < N; k++ ){
					if( ( i & ( 1 << k ) ) == 0 ){
						cost[k][i|(1<<k)] = min( cost[k][i|(1<<k)], cost[j][i] + dis[j][k] );
					}
				}
			}
		}
	}

	for( int i = 1; i < ( 1 << N ); i++ ){
		for( int j = ( ( i - 1 ) & i ); j; j = ( ( j - 1 ) & i ) ){
			np[i] = min( np[i], np[j|1] + np[(i-j)|1] );
		}
	}

	return np[(1<<N)-1];
}

int main(){

	while( scanf( "%d%d", &N, &M ) != EOF ){

		for( int i = 0; i < N; i++ ){
			scanf( "%lf%lf", &p[i].x, &p[i].y );
		}
		
		for( int i = 0; i < N; i++ ){
			scanf( "%d", &weight[i] );
			maxweight = max( weight[i], maxweight );
		}

		initial();

		int ans1 = solve_first();
		if( ans1 == -1 ){
			cout << -1 << " " << -1 << endl;
			continue;
		}

		cout << ans1 << " " << solve_second() << endl;
	}
	return 0;
}


 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值