北大ACM2686——Traveling by Stagecoach~~状态压缩DP

最近才看书,看到状态压缩。对于状态压缩DP,其实就是集合上的DP。

这需要我们了解一些位运算:

集合{0,1,2,3,....,n-1}的子集可以用下面的方法编码成整数

像这样,一些集合运算就可以用如下的方法来操作:

1.空集....................0

2.只含有第i个元素的集合{i}................1 << i

3.含有全部n个元素的集合{0,1,2,3,....,n - 1}.............(1 << n) - 1

4.判断第i个元素是否属于集合S.................................if(S >> i & 1)

5.向集合中加入第i个元素S ∪ {i}...............................S | 1 << i

6.从集合中除去第i个元素S \ {i}..................................S & ~(1 << i)

7.集合S和T的并集S∪T...............................................S | T

8.集合S和T的交集S∩T................................................S & T

而题目的意思是:一个人在m个城市的国家旅行,他有n张车票,这个国家有p条路,一条路连接两个城市,他要从a城市到b城市,从一个城市到另一个城市所需要的时间是路的长度除以车票的面值,面值是多少表示可以有多少匹马来拉,求最短的时间。

这题,不能直接用最短路径的算法来求解,有车票的限制。我们将在第i个城市看作一个状态,剩下的车票为一个集合S,从这个城市出发,使用一张车票到达城市j,现在他在第j个城市,状态为S \ {i},花费的时间就是路的长度除以车票的面值。

下面的是 AC的代码:

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

const double INF = 10000000000.00;
int n, m, p, a, b;
int ticket[10];
int map[32][32];

double dp[1 << 10][32];

double min(double a, double b)   //取最小值
{
	return a > b ? b : a;
}

void solve()
{
	int i, j;
	for(i = 0; i < 1 << n; i++) //初始化dp数组
	{
		for(j = 0; j < 32; j++)
			dp[i][j] = INF;
	}
	dp[(1 << n) - 1][a - 1] = 0;
	double res = INF;
	for(int S = (1 << n) - 1; S >= 0; S--)  //集合S
	{
		res = min(res, dp[S][b - 1]);
		for(int v = 0; v < m; v++)
		{
			for(i = 0; i < n; i++)        //枚举车票
			{
				if(S >> i & 1)            //判断第i个车票是否属于集合S
				{
					for(int u = 0; u < m; u++)
					{
						if(map[v][u] >= 0) //城市v到u有路,使用第i个车票从v到u
						{
							dp[S & ~(1 << i)][u] = min(dp[S & ~(1 << i)][u], dp[S][v] + double(map[v][u]) / ticket[i]);
						}
					}
				}
			}
		}
	}
	if(res == INF)
		printf("Impossible\n");
	else
		printf("%.3lf\n", res);
}

int main()
{
//	freopen("data.txt", "r", stdin);
	int i, x, y, z;
	while(cin >> n >> m >> p >> a >> b)
	{
		memset(map, -1, sizeof(map));
		if(n == 0 && m == 0 && p == 0 && a == 0 && b == 0)
			break;
		for(i = 0; i < n; i++)   //输入数据
			cin >> ticket[i];
		for(i = 0; i < p; i++)
		{
			cin >> x >> y >> z;
			map[x - 1][y - 1] = z;
			map[y - 1][x - 1] = z;
		}
		solve();
	}
	return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-05 12:35:46

北大ACM2686——Traveling by Stagecoach~~状态压缩DP的相关文章

poj2686(Traveling by Stagecoach)状态压缩dp

Description Once upon a time, there was a traveler. He plans to travel using stagecoaches (horse wagons). His starting point and destination are fixed, but he cannot determine his route. Your job in this problem is to write a program which determines

POJ 2686 Traveling by Stagecoach (状态压缩DP)

Traveling by Stagecoach Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 2776   Accepted: 996   Special Judge Description Once upon a time, there was a traveler. He plans to travel using stagecoaches (horse wagons). His starting point and

Traveling by Stagecoach 状态压缩裸题

Traveling by Stagecoach dp[s][v]  从源点到达  v,状态为s,v的最小值.  for循环枚举就行了. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 #include <string> 7 #include <vector>

Traveling by Stagecoach(POJ-2686)(状态压缩DP)

状态压缩DP和普通DP唯一的区别就是它所枚举的对象不再是一个整数,而是一个集合,解决的策略就是利用二进制将这个集合压缩成一个整数. 对于该题,dp[s][v]表示:s表示在该城市剩下的车票集合,v表示在城市v,dp表示在该状态的最小话费. 影响决策的因素有一下几个: 1.一共使用哪几个车票(包括数量和种类) 2.当前从哪个城市到哪个城市 3.使用哪个车票完成两个城市的转移 所以一共需要枚举4个量,用4重循环完成状态转移. #include<cstdio> #include<cstring

POJ 3254 Corn Fields 状态压缩DP (C++/Java)

http://poj.org/problem?id=3254 题目大意: 一个农民有n行m列的地方,每个格子用1代表可以种草地,而0不可以.放牛只能在有草地的,但是相邻的草地不能同时放牛, 问总共有多少种方法. 思路: 状态压缩的DP. 可以用二进制数字来表示放牧情况并判断该状态是否满足条件. 这题的限制条件有两个: 1.草地限制. 2.相邻限制. 对于草地限制,因为输入的时候1是可以种草地的. 以"11110"草地分析,就只有最后一个是不可以种草的.取反后得00001  .(为啥取反

HDU1565(状态压缩dp)

方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 8170    Accepted Submission(s): 3095 Problem Description 给你一个n*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数

HDU 3001【状态压缩DP】

题意: 给n个点m条无向边. 要求每个点最多走两次,要访问所有的点给出要求路线中边的权值总和最小. 思路: 三进制状态压缩DP,0代表走了0次,1,2类推. 第一次弄三进制状态压缩DP,感觉重点是对数据的预处理,利用数组分解各个位数,从而达到类似二进制的目的. 然后就是状态的表示,dp[s][i]表示状态s时到达i的最优值. 状态转移也一目了然,不废话. #include<stdio.h> #include<string.h> #include<algorithm> u

Victor and World(spfa+状态压缩dp)

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=5418 Victor and World Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/131072 K (Java/Others)Total Submission(s): 958    Accepted Submission(s): 431 Problem Description After trying hard fo

poj 3311 Hie with the Pie(状态压缩dp)

Description The Pizazz Pizzeria prides itself in delivering pizzas to its customers as fast as possible. Unfortunately, due to cutbacks, they can afford to hire only one driver to do the deliveries. He will wait for 1 or more (up to 10) orders to be