hdu--4856--状压dp

我都不想将bfs这3个字写在标题里...bfs没那么简单

就是求出任意两个管子之间的最短距离  但这边不能直接用spfa dij啊什么的   但感觉现在的bfs就有点相当于退化版的最短路。。

这题的重点还是在完成上面的Precompute后 接下去的求tsp操作

这边应该是最简单的 没有多余的难度增加的求tsp

我这提供了2种 我分别加上注释

tot 就是总的状态

 1     for( int i = 2 ; i<=tot ; i++ )//枚举状态
 2     {
 3         for( int j = 1 ; j<=m ; j++ )//枚举管子
 4         {
 5             if( i&(1<<j) ) //在该状态下已经走过
 6                 continue;
 7             for( int k = 1 ; k<=m ; k++ )
 8             {
 9                 if( i&(1<<k) ) //在该状态下已经走过 去 未达到的管子
10                     dp[ i|(1<<j) ][j] = min( dp[ i|(1<<j) ][j] , dp[i][k]+dist[k][j] );
11             }
12         }
13     }
 1     for( int i = 2 ; i<=tot ; i++ )//枚举状态
 2     {
 3         for( int j = 1 ; j<=m ; j++ )//枚举管子
 4         {
 5             if( i&(1<<j) )//从该状态下已经到达的管子出发
 6             {
 7                 for( int k = 1 ; k<=m ; k++ )
 8                 {
 9                     if( !( i&(1<<k) ) )//从该状态下已经到达的管子出发 去 还没有到达的管子
10                         dp[ i|(1<<k) ][k] = min( dp[ i|(1<<k) ][k] , dp[i][j] + dist[j][k] );
11                 }
12             }
13         }
14     }

其实2者没什么差 就是写法上有点区别 我觉得第二种写法更好.

  1 #include <iostream>
  2 #include <cstring>
  3 #include <queue>
  4 #include <algorithm>
  5 using namespace std;
  6
  7 int n , m , tot;
  8 const int size = 20;
  9 const int inf = 0x3f3f3f3f;
 10 int dir[4][2] = {1,0,-1,0,0,1,0,-1};
 11 int dp[1<<16][size];
 12 bool vis[size][size];
 13 int dist[size][size];
 14 char mp[size][size];
 15
 16 struct data
 17 {
 18     int sx , sy , endx , endy;
 19     int step;
 20     data(){};
 21     data( int u , int v , int w ):endx(u),endy(v),step(w){};
 22 }pipe[size];
 23
 24 void init( )
 25 {
 26     memset( dp , inf , sizeof(dp) );
 27     for( int i = 1 ; i<=m ; i++ )
 28         dp[1<<i][i] = 0;
 29 }
 30
 31 int bfs( int from , int to )
 32 {
 33     queue<data> q;
 34     data now;
 35     now.endx = pipe[from].sx;
 36     now.endy = pipe[from].sy;
 37     now.step = 0;
 38     q.push( now );
 39     memset( vis , false , sizeof(vis) );
 40     vis[ now.endx ][ now.endy ] = true;
 41     while( !q.empty( ) )
 42     {
 43         now = q.front();
 44         q.pop();
 45         if( now.endx == pipe[to].endx && now.endy == pipe[to].endy )
 46         {
 47             return now.step;
 48         }
 49         for( int i = 0 ; i<4 ; i++ )
 50         {
 51             int xx = now.endx + dir[i][0];
 52             int yy = now.endy + dir[i][1];
 53             if( xx >=1 && xx<=n && yy>=1 && yy<=n && mp[xx][yy]!=‘#‘ && !vis[xx][yy] )
 54             {
 55                 vis[xx][yy] = true;
 56                 q.push( data(xx,yy,now.step+1) );
 57             }
 58         }
 59     }
 60     return inf;
 61 }
 62
 63 void solve( )
 64 {
 65     for( int i = 1 ; i<=m ; i++ )
 66     {
 67         for( int j = 1 ; j<=m ; j++ )
 68         {
 69             if( i==j )
 70                 dist[i][j] = 0;
 71             else
 72                 dist[i][j] = bfs( i , j );
 73         }
 74     }
 75     for( int i = 2 ; i<=tot ; i++ )
 76     {
 77         for( int j = 1 ; j<=m ; j++ )
 78         {
 79             if( i&(1<<j) )
 80                 continue;
 81             for( int k = 1 ; k<=m ; k++ )
 82             {
 83                 if( i&(1<<k) )
 84                     dp[ i|(1<<j) ][j] = min( dp[ i|(1<<j) ][j] , dp[i][k]+dist[k][j] );
 85             }
 86         }
 87     }
 88 }
 89
 90 int main()
 91 {
 92     cin.sync_with_stdio(false);
 93     int ans;
 94     while( cin >> n >> m )
 95     {
 96         init( );
 97         for( int i = 1 ; i<=n ; i++ )
 98         {
 99             for( int j = 1 ; j<=n ; j++ )
100             {
101                 cin >> mp[i][j];
102             }
103         }
104         for( int i = 1 ; i<=m ; i++ )
105         {
106             cin >> pipe[i].sx >> pipe[i].sy >> pipe[i].endx >> pipe[i].endy;
107         }
108         tot = ( 1<<(m+1) ) - 2;
109         init( );
110         solve( );
111         ans = inf;
112         for( int i = 1 ; i<=m ; i++ )
113         {
114             ans = min( ans , dp[ tot ][i] );
115         }
116         if( ans==inf )
117             cout << -1 << endl;
118         else
119             cout << ans << endl;
120     }
121     return 0;
122 }

today:

  first love

时间: 2024-09-29 22:52:43

hdu--4856--状压dp的相关文章

HDU 4284 状压dp+spfa堆优化

题意: 给定n个点 m条无向边 d元. 下面m行表示每条边 u<=>v 以及花费 w 下面top 下面top行 num c d 表示点标为num的城市 工资为c 健康证价格为d 目标是经过给定的top个城市,当到达该城市时,必须马上购买该城市的健康证并打工赚钱(每个城市只打工1次) 问从1城市出发,最后回到1城市,能否收集到所有的健康证 思路: 由于top很小,所以状压dp dp[i][tmp]表示当前处于i点 经过城市的状态为tmp时 身上最多的钱. 首先对dis数组floyd 跑出最短路,

hdu 4906 状压dp

/* ID: neverchanje PROG: LANG: C++11 */ #include<vector> #include<iostream> #include<cstring> #include<string> #include<algorithm> #include<cmath> #include<cstdio> #include<set> #include<queue> #includ

HDU 4892 状压dp

[BestCoder Round #5]冠军的奖励是小米3手机一部 恭喜福州大学杨楠获得[BestCoder Round #4]冠军(iPad Mini一部) <BestCoder用户手册>下载 Defence of the Trees Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 224    Accepted Submiss

HDU 3001 状压DP

有道状压题用了搜索被队友骂还能不能好好训练了,, hdu 3001 经典的状压dp 大概题意..有n个城市 m个道路  成了一个有向图.n<=10: 然后这个人想去旅行.有个超人开始可以把他扔到任意的一个城市..然后他就在城市之间游荡.要满足他要游玩所有的城市..并且.每个城市最多去两次.要求路程最短..如果他不能游完所有的城市,,那么..就输出-1  否则 输出最短距离 如果用搜索...不靠谱  然后用搜索,, 怎么压缩?? 用一个整型数 i 表示他现在的状态..显然一个城市是要用两位..00

Travel(HDU 4284状压dp)

题意:给n个城市m条路的网图,pp在城市1有一定的钱,想游览这n个城市(包括1),到达一个城市要一定的花费,可以在城市工作赚钱,但前提有工作证(得到有一定的花费),没工作证不能在该城市工作,但可以走,一个城市只能工作一次,问pp是否能游览n个城市回到城市1. 分析:这个题想到杀怪(Survival(ZOJ 2297状压dp) 那个题,也是钱如果小于0就挂了,最后求剩余的最大钱数,先求出最短路和 Hie with the Pie(POJ 3311状压dp) 送披萨那个题相似. #include <

hdu 1185 状压dp 好题 (当前状态与上两行有关系)

/* 状压dp 刚开始&写成&&看了好长时间T0T. 状态转移方程 dp[i][k][j]=Max(dp[i][k][j],dp[i-1][l][k]+num[i][j]);(第i行的第j个状态有上一行的第k个状态得到) num[i][j]有两个功能,第一:判断第i行第j个状态是否合法 第二:判断第i行第j个状态的数目 */ #include<stdio.h> #include<string.h> #define N 110 int dp[N][N][N];

HDU 5823 (状压dp)

Problem color II 题目大意 定义一个无向图的价值为给每个节点染色使得每条边连接的两个节点颜色不同的最少颜色数. 对于给定的一张由n个点组成的无向图,求该图的2^n-1张非空子图的价值. n <= 18 解题分析 官方题解: 直接状压dp就行了,f[S]表示点集S的色数,枚举子集转移(子集是独立集).这样是3^n的. 一个复杂度更优的做法是把所有独立集都预处理出来,然后作n次or卷积.这样是n^2*2^n的. 枚举子集的子集的时间复杂度是3^n 啊 . 即 sigma( C(n,k

hdu 3254 (状压DP) Corn Fields

poj 3254 n乘m的矩阵,1表示这块区域可以放牛,0,表示不能,而且不能在相邻的(包括上下相邻)两个区域放牛,问有多少种放牛的方法,全部不放也是一种方法. 对于每块可以放牛的区域,有放或者不放两种选择,状压DP,dp[i][j]表示第 i 行以state[j]这种状态的时候和方法取值. 具体的参考http://www.tuicool.com/articles/JVzMVj 写的很详细. 1 #include<cstdio> 2 #include<cstring> 3 #inc

HDU 6321 (状压dp)

题目大意:: 为给你n个点(n<=10,nn<=10,n) 初始时没有边相连 然后有m个操作(m<=30000m<=30000) 每次可以添加一条边或删除一条边 允许有重边 要求每次操作过后输出选这个图中不相交的k条边有多少种不同的方案 (k=1,2,3--n/2) 题目分析: n最大只有10 , 所以很容易就可以想到状压DP , 但是我在打的时候并没有想出继承状态 , 后来看了题解才略有一丝感悟: 首先一个特别容易看出的状态是每加/减一条边后的状态是由前一个状态转移过来的 : 而

hdu 5471(状压DP or 容斥)

想了最复杂的思路,用了最纠结的方法,花了最长的时间,蒙了一种规律然后莫名其妙的过了. MD 我也太淼了. 后面想了下用状压好像还是挺好写的,而且复杂度也不高.推出的这个容斥的规律也没完全想透我就CAO. Count the Grid Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 400    Accepted Submission(s)