poj2686 状压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城市,从一个城市到另一个城市所需要的时间是路的长度除以车票的面值,面值表示可以有多少匹马来拉,求最短的时间。

题解:看代码,主要就是状压dp+dijkstra

还有一点就是min只能用于整形,这样的话要算float的话就只能用宏定义了

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<cstdio>
#include<iomanip>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define pi acos(-1)
#define ll long long
#define mod 10007
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define MIN(a,b) a<b ? a:b

using namespace std;

const double g=10.0,eps=1e-9;
const int N=9,maxn=30,inf=1<<29;

int n,m,p,a,b,t[maxn];
int d[maxn][maxn];
double dp[1<<N][maxn];

void solve()
{
    for(int i=0;i< 1<<n;i++)//从0到1<<n是所以子集
        fill(dp[i],dp[i]+m,inf);//把dp初始化
    dp[(1<<n)-1][a-1]=0;//起始点设为0,就是dijkstra算法
    double res=inf;
    for(int s=(1<<n)-1;s>=0;s--)
    {
        res=MIN(res,dp[s][b-1]);//记录答案
        for(int v=0;v<m;v++)//起点
            for(int i=0;i<n;i++)//这是车票
                if(s>>i&1)//判断第i个元素是否属于s
                    for(int u=0;u<m;u++)//终点
                        if(d[v][u]>=0)//使用车票i,从v到u
                            dp[s& ~(1<<i)][u]=MIN(dp[s& ~(1<<i)][u],dp[s][v]+(double)d[v][u]/t[i]);
    }
    if(res==inf)cout<<"Impossible"<<endl;
    else cout<<res<<endl;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout<<setiosflags(ios::fixed)<<setprecision(3);
    while(cin>>n>>m>>p>>a>>b){
        if(!n&&!m)break;
        for(int i=0;i<n;i++)cin>>t[i];
        memset(d,-1,sizeof d);//距离初始化为-1
        for(int i=0;i<p;i++)
        {
            int x,y,z;
            cin>>x>>y>>z;
            x--;
            y--;
            d[x][y]=d[y][x]=z;//保存距离信息,这是无向无环图
        }
        solve();
    }
    return 0;
}
View Code

 

posted @ 2017-05-12 14:19  walfy  阅读(186)  评论(0编辑  收藏  举报