POJ 3411 Paid Roads

地址:http://poj.org/problem?id=3411

题意:给了N个城市,给出若干路径,可从a到b,若之前经过过c城市则收费p,否则收费r,计算从1到n城市的路费最小值。

思路:

1 . 状态压缩DP。用dp [ i ] [ j ] 表示在i状态下到达j城市的最小收费,其中i用二进制形式表示所有城市的访问情况。

2 . 动态规划的方法类似spfa算法,从dp [ 1 ] [ 1 ] 开始对它能影响到的城市的各种情况进行松弛(若到达N城市显然没有必要入队再计算),显然最后的结果是存储在dp [ x ] [ n ] (0<x<( 1<<n ))中的最小值。

PS:

居然写代码的时候把p,r写反了,这英语啊~~~~

还有,记得n=1的特殊情况,部分代码可能会出现n=1的情况下cout<<"impossile"的问题,比如说,我。。。

最后吐槽下,明明是状态压缩DP,为什么分类在中级搜索里,理解不能啊!!!

#include<iostream>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;

#define MAX 1000000000
int dp[(1<<10)][11];
int cost,n,m;
struct node{
       int i,j;     
};

struct edge{
       int b,c,p,r;      
};
vector<edge>  e[11];

void spfa(){
        int i,j,k,vis,a,b,c,p,r;   
        dp[1][1]=0;
        node t;
        t.i=1;
        t.j=1;
        queue<node> q;
        q.push(t);
        while(!q.empty()){
                node fm=q.front();
                q.pop();
                vis=fm.i;
                a=fm.j;
                for(k=0;k<e[a].size();k++){
                       b=e[a][k].b;
                       c=e[a][k].c;
                       p=e[a][k].p;
                       r=e[a][k].r;
                       int new_cost = (vis&(1<<(c-1)) ? p :r ) ;
                       new_cost+=dp[vis][a]; 
                       int new_vis = vis;
                       if((vis&(1<<(b-1)))==0) new_vis+=(1<<(b-1));
                       if(new_cost<dp[new_vis][b]){
                                t.i=new_vis;
                                t.j=b;
                                dp[new_vis][b]=new_cost;
                                if(b!=n){
                                        q.push(t);
                                }
                                else{
                                     if(cost>dp[new_vis][n])
                                             cost=dp[new_vis][n];   
                                }                            
                       }                                                  
                }               
        }
        return ;
}

int main(){
    int i,j;
    while(cin>>n>>m){
             for(i=1;i<11;i++)
                  e[i].clear();
             for(i=0;i<(1<<10);i++)
                    for(j=0;j<11;j++){
                          dp[i][j]=MAX;             
             }
             cost=MAX;
             for(i=0;i<m;i++){
                  int a;
                  edge k;
                  cin>>a>>k.b>>k.c>>k.p>>k.r;                 
                  e[a].push_back(k);
             }
             spfa();
             if(n==1) cost=0;
             if(cost==MAX)
                          cout<<"impossible"<<endl;
             else
                          cout<<cost<<endl;
    }
    return 0;    
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值