一开始学状压DP难以理解,后来从TSP开始,终于入门了nice!!!!

旅行商问题 :    给定n个城市和两两相互的距离 ,求一条路径经过所有城市,并且路径达到最下仅限于;

朴树想法: 做n个城市的排列 复杂度为n!,  但显然不可以;

首先介绍什么是状态压缩 , 本题的状态压缩就是把每一个城市分成两种状态:0代表还没有经过这座城市,1代表已经经过了这座城市,(这里就是状态)

现在,按照一定的顺序给每个城市一个编号(dp一定要有顺序性),那么已经走过的城市的状态就可以压缩成一个数(十进制的数)(这里就是压缩)。

如果有5座城市:

    初始状态:0 0 0 0 0   :表示的是都没有经历过
    如果进入了下一个状态,比如第一座城市已经走过(这里是从右向左的顺序) 就为00001;
我们现在就定义一个  dp [i] [j] 表示的是这种状态下最后一个走到的城市是第j做城市    (这里的序号都是从1开始)  的最短路径,注意这里 i 和 j 有一定是联系
具体用式子说 :    (i&1<<j)==1, 就是说 i里面在 j 这个城市一定是访问过的.否者是没有意义的

状态转移: 这个状态由多个状态转移而来,dp[ i ][ j]=min( dp[ i ^ (1<<j) ][ k ] + dis[ k ][ j ]  );   k为所有非j且在i状态中存在;(这样的转移是没有后效性的)保证最优子结构

for (int i = ; i <= n; i++)
dp[<<(i - )][i] = ;
int ans = inf;
for (int i = ; i < (<<n); i++) //状态的个数,从n个0到n个1
for (int j = ; j <= n; j++)
{
if (i&(<<(j - ))) //必须是访问过的点j才可以,访问过的才知道最优子结构
{
for (int k = ; k <= n; k++)
if (i&(<<(k - )) != && g[k][j] != -) //必须是访问过的k点且边存在
dp[i][j] = min(dp[i^(<<(j - ))][k] + g[k][j], dp[i][j]);
}
if (i == (<<n) - )
ans = min(ans, dp[i][j]);
}
if (ans == inf)
return -;
return ans;

接下来介绍一道例题

题目:
2230: Cheap deliveries

Time Limit: 2 Sec  Memory Limit: 64 MB   64bit IO Format: %lld
Submitted: 40  Accepted: 16
[Submit][Status][Web Board]

Description

Abu runs a delivery service where he deliver items from one city to another. As with any business, Abu wants to decrease his cost as much as possible. The further he travel, the more fuel he will use.

In any particular day, Abu have k items to deliver. Each item needs to be delivered from a start city to a destination city. Each city is represented by an integer. Because of his business policies, he can only deliver one item at a time. However, he can deliver the items in any order that he wants, as long as he deliver all of them. So, everyday he starts at an item's start city and deliver the item to its destination city. Then, he goes to the next items's start city and deliver the item to the its destination city. And, he does this until he does not have any item left to deliver.

From experimentation, Abu notices that the distance he travels change if he change the order of his delivery. He thought, he can save a lot of money if he knows the best delivery order. He knows that you are very good at solving this kind of problem. So he wants you to solve it for him. Given a list of cities, a list of roads between the cities (and the road's length), and a description of deliveries he must do, determine what is the minimum total travel distance, given that he execute his delivery in the most efficient order.

Every road is bidirectional and there can be more than one road between two cities. Abu can use any road as many time as he wants.

Input

The first line consists of two integer n, m, k (2 ≤ n, m ≤ 104), (1 ≤ k ≤ 18) which is the number of cities, the number of roads and the number of items respectively.

The next m line each consist of 3 integers, ui, vi, li (1 ≤ ui, vi ≤ 10^4), (1 ≤ li ≤ 10^6), which denotes that a road exists from city ui to vi with length li.

The next k line each consist of 2 integers, fi, di (1 ≤ fi, di ≤ 10^4) which denotes that the ith item is from city fi and its destination is city di.

Output

A single integer, which is the minimum total travel distance given that Abu deliver all items optimally, or -1 if its is impossible for him to deliver all items.

Sample Output 1:

题目简要: 给定一张n个点 m条路的图 和k对结点,要求选择一条路径(可以重复)且路径最短,完全就是TSP问题的变形,只不过是把一个城市转化为了一段路径(感觉像是网络流里面的拆点);先把每个点之间的距离算出来直接做就完事了

#include <iostream>
#include <cstdio>
#include <algorithm>
#include<string.h>
#include<queue>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 500000+10;
inline int gi() {
int date = 0,m = 1;
char ch = 0;
while(ch!='-'&&(ch<'0'||ch>'9'))ch = getchar();
if(ch=='-') {
m = -1;
ch = getchar();
}
while(ch>='0' && ch<='9') {
date = date*10+ch-'0';
ch = getchar();
}
return date*m;
}
struct Edge {
int to, w,nxt;
} e[maxn];
struct node2 {
bool friend operator < (node2 n1, node2 n2) {
return n1.d > n2.d;
}
int id, d;
};
int head[maxn], cnt=0;
int dis[maxn];
int finish[maxn];
int n, m,k;
inline void add(const int& from, const int& to,const int&w) {
++cnt;
e[cnt].to = to;
e[cnt].nxt = head[from];
e[cnt].w=w;
head[from] = cnt;
}
void dij(int s) {
memset(dis,0x3f,sizeof(dis));
memset(finish,0,sizeof(finish));
priority_queue<node2> q;
dis[s] = 0;
node2 nn1;
nn1.id = s;
nn1.d = dis[s];
q.push(nn1);
while(!q.empty()) {
node2 nn2 = q.top();
q.pop();
int now = nn2.id;
if(finish[now])continue;
else finish[now] = 1;
for(int i = head[now]; i ; i=e[i].nxt) {
int nv=e[i].to;
if(!finish[nv] && e[i].w+dis[now] < dis[nv]) {
dis[nv] = e[i].w + dis[now];
node2 nn3;
nn3.id = nv;
nn3.d = dis[nv];
q.push(nn3);
} }
}
}
int klist[20][2];
int d[20][20];
int dp[1<<18][20];
int main() {
int ans=inf;
int i,j,v;
memset(head,0,sizeof(head));
memset(d,inf,sizeof(d));
n=gi(),m=gi(),k=gi();
for( i=0; i<m; i++) {
int u=gi(),v=gi(),w=gi();
add(u,v,w);
add(v,u,w);
}
for( i=1; i<=k; i++) {
int u=gi(),v=gi();
klist[i][0]=u;
klist[i][1]=v;
}
for( i=1; i<=k; i++) {
dij(klist[i][0]);
for(j=1; j<=k; j++) {
d[i][j]=dis[klist[j][1]];
}
}
memset(dp,inf,sizeof(dp));
for(int i=0; i<k; i++) {
dp[1<<i][i+1]=d[i+1][i+1];
}
for( i=0; i<(1<<k); i++) {
for( j=0; j<k; j++) {
if( i&(1<<j)) {
for(v = 0; v < k; v++) {
if((i&(1<<v))!=0&&d[j+1][v+1]!=inf) {
dp[i][j+1]=min(dp[i][j+1],dp[i^(1<<j)][v+1]+d[j+1][v+1]+d[j+1][j+1]);
}
}
if(i== (1<<k)-1) {
ans = min(ans,dp[i][j+1]);
}
}
}
}
if(ans==inf)ans=-1;
cout<<ans<<endl;
return 0;
}

  

     

状压DP 从TSP问题开始入门哦的更多相关文章

  1. HDU 5067 Harry And Dig Machine(状压DP)(TSP问题)

    题目地址:pid=5067">HDU 5067 经典的TSP旅行商问题模型. 状压DP. 先分别预处理出来每两个石子堆的距离.然后将题目转化成10个城市每一个城市至少经过一次的最短时间 ...

  2. POJ3311 Hie with the Pie(状压DP,Tsp)

    本题是经典的Tsp问题的变形,Tsp问题就是要求从起点出发经过每个节点一次再回到起点的距离最小值,本题的区别就是可以经过一个节点不止一次,那么先预处理出任意两点之间的最短距离就行了,因为再多走只会浪费 ...

  3. [状压dp]经典TSP

    0出发 每个顶点经过一次 回到0 最小花费. O($n^2 \times 2^n$) 记忆化搜索: // s: 已经访问过的节点状态 v: 出发位置 int dfs(int s, int v) { ) ...

  4. hdu3247Resource Archiver (AC自动机+最短路+状压dp)

    Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 100000/100000 K (Java/Others) Total Submis ...

  5. poj3311 TSP经典状压dp(Traveling Saleman Problem)

    题目链接:http://poj.org/problem?id=3311 题意:一个人到一些地方送披萨,要求找到一条路径能够遍历每一个城市后返回出发点,并且路径距离最短.最后输出最短距离即可.注意:每一 ...

  6. TSP问题之状压dp法

    首先,我们先来认识一下什么叫做TSP问题 旅行商问题,即TSP问题(Traveling Salesman Problem)又译为旅行推销员问题.货郎担问题,是数学领域中著名问题之一.假设有一个旅行商人 ...

  7. POJ3311 Hie with the Pie 【状压dp/TSP问题】

    题目链接:http://poj.org/problem?id=3311 Hie with the Pie Time Limit: 2000MS   Memory Limit: 65536K Total ...

  8. poj3254状压DP入门

    G - 状压dp Crawling in process... Crawling failed Time Limit:2000MS     Memory Limit:65536KB     64bit ...

  9. 状压dp入门

    状压dp的含义 在我们解决动态规划题目的时候,dp数组最重要的一维就是保存状态信息,但是有些题目它的具有dp的特性,并且状态较多,如果直接保存的可能需要三维甚至多维数组,这样在题目允许的内存下势必是开 ...

随机推荐

  1. Android_存储之SharedPreferences

    一.概述 SharedPreferences是一种轻量级的数据存储方式,采用键值对的存储方式. SharedPreferences只能存储少量数据,大量数据不能使用该方式存储,支持存储的数据类型有bo ...

  2. [JavaWeb基础] 004.用JSP + SERVLET 进行简单的增加删除修改

    上一次的文章,我们讲解了如何用JAVA访问MySql数据库,对数据进行增加删除修改查询.那么这次我们把具体的页面的数据库操作结合在一起,进行一次简单的学生信息操作案例. 首先我们创建一个专门用于学生管 ...

  3. 百万年薪架构师一文整理RabbitMQ、ActiveMQ、RocketMQ、Kafka

    一般来说,大型应用通常会被拆分成多个子系统,这些子系统可能会部署在多台机器上,也可能只是一台机器的多个进程中,这样的应用就是分布式应用.在讨论分布式应用时,很多初学者会把它和集群这个概念搞混,因为从部 ...

  4. C++ 海量代码 排查内存/GDI泄漏历程

    排查分两大部分: 1.代码静态分析,通过Code Review查找不合规范的代码点: 2.运行目标软件,结合内存监控工具,分析目标软件的代码,定位内存泄漏点. 目前能找到的代码静态分析软件:Cover ...

  5. Unity 离线建造系统

    很多游戏,特别是养成类手游,都会有自己独特的建造系统,一个建造装置的状态循环或者说生命周期一般是这样的: 1.准备建造,设置各项资源的投入等 2.等待一段倒计时,正在建造中 3.建造结束,选择是否收取 ...

  6. JAVASE(十二) Java常用类: 包装类、String类、StringBuffer类、时间日期API、其他类

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 1.包装类 1 .1 八个包装类 ​ 1. 2 基本数据类型,包装类,String者之间的转换 ​ 2. ...

  7. Java实现 LeetCode 404 左叶子之和

    404. 左叶子之和 计算给定二叉树的所有左叶子之和. 示例: 3 / \ 9 20 / \ 15 7 在这个二叉树中,有两个左叶子,分别是 9 和 15,所以返回 24 /** * Definiti ...

  8. Java实现N*N矩阵旋转(360度)

    N*N矩阵旋转 Description 给你一个n*n的矩阵,你的任务是将它逆时针旋转角度d. [输入] 输入的第一个数为T,表示接下来有T组数据. 每组数据的格式如下: 第一行为两个整数n,d.1& ...

  9. java实现第五届蓝桥杯年龄巧合

    年龄巧合 小明和他的表弟一起去看电影,有人问他们的年龄.小明说:今年是我们的幸运年啊.我出生年份的四位数字加起来刚好是我的年龄.表弟的也是如此.已知今年是2014年,并且,小明说的年龄指的是周岁. 请 ...

  10. Linux目录处理命令cd、pwd、rmdir、cp、mv、rm详解

    命令cd详解 命令cd(英文原意:change directory),命令路径及执行权限为: 可以看到它的路径为/usr/bin/cd,因此,它的执行权限是所有用户 基本功能是切换目录,例如:cd . ...