zoukankan      html  css  js  c++  java
  • 【题解】Paid Roads [SP3953] [Poj3411]

    【题解】Paid Roads [SP3953] [Poj3411]

    传送门:( ext{Paid}) ( ext{Roads}) ( ext{[SP3953]}) ( ext{[Poj3411]})

    【题目描述】

    给出一张 (n) 个点 (m) 条边的有向图。对于每条边 ((x,y)),如果之前经过 (z) 点,那么费用为 (p),否则为 (r)。求 (1)(n) 的最小费用。如果无法到达则输出 “ ( ext{impossible}) ”。

    【样例】

    样例输入:
    4 5
    1 2 1 10 10
    2 3 1 30 50
    3 4 3 80 80
    2 1 2 10 10
    1 3 2 10 50
    
    样例输出:
    110
    

    【数据范围】

    (100 \%:) (1 leqslant n,m leqslant 10,) (0 leqslant p_i,r_i leqslant 100)


    【分析】

    由于边的费用涉及到了是否经过某个点, 而且(n) 较小,因此可以考虑状压。

    将每个点 (i) 分为 (2^n-1) 层,第 (j) 层表示当前在第 (i) 个点,状态为 (j)(二进制第 (k) 位为 (1) 就表示已经经过了点 (k)(0) 表示还未经过)的状态,跑一遍 ( ext{dijkstra}) 或者 ( ext{SPFA}) 即可。

    也可以开一个二维的 ( ext{dis}) 数组,(dis[i][j]) 表示当前在点 (i),状态为 (j) 的最短路,在最短路算法里面按照 (j) 分类更新 (dis)

    另外注意一下坑点:每个点可经过多次

    个人喜欢把所有的点全部建好,直接跑裸的最短路(就像写网络流那样)。

    第二种写法代码就不放了。

    【Code】

    #include<algorithm>
    #include<cstdio>
    #include<queue>
    #define LL long long
    #define Re register int
    using namespace std;
    const int N=10300,M=2e4+3,inf=2e9;
    int n,m,x,y,z,p,r,o,V,ans,dis[N],pan[N],head[N];
    struct QWQ{int x,d;inline bool operator<(QWQ O)const{return d>O.d;}};
    struct QAQ{int w,to,next;}a[M<<1];priority_queue<QWQ>Q;
    inline void add(Re x,Re y,Re z){a[++o].w=z,a[o].to=y,a[o].next=head[x],head[x]=o;}
    inline void in(Re &x){
        Re f=0;x=0;char c=getchar();
        while(c<'0'||c>'9')f|=c=='-',c=getchar();
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
        x=f?-x:x;
    }
    inline void dijkstra(Re st){
        for(Re i=0;i<=n*V;++i)dis[i]=inf,pan[i]=0;//注意初始化时应扫描到n*V
        Q.push((QWQ){st,dis[st]=0});
        while(!Q.empty()){
            Re x=Q.top().x;Q.pop();
            if(pan[x])continue;
            pan[x]=1;
            for(Re i=head[x],to;i;i=a[i].next)
                if(dis[to=a[i].to]>dis[x]+a[i].w)
                    Q.push((QWQ){to,dis[to]=dis[x]+a[i].w});
        }
    }
    inline int Poi(Re i,Re j){return j+(i-1)*V;}//当前在点i状态为j
    int main(){
        // freopen("123.txt","r",stdin);
        in(n),in(m),V=(1<<n)-1;
        while(m--){
            in(x),in(y),in(z),in(p),in(r);
            for(Re j=0;j<=V;++j)
                if(j&(1<<x-1))//如果j中包含了x,由于点可经过多次,所以不必判断y的情况
                    if(j&(1<<z-1))add(Poi(x,j),Poi(y,j|(1<<y-1)),p);//已经经过了z
                    else add(Poi(x,j),Poi(y,j|(1<<y-1)),r);//还没有经过z
        }
        dijkstra(Poi(1,1));ans=inf;//出发点为:只经过了1的状态,当前在点1
        for(Re j=0;j<=V;++j)ans=min(ans,dis[Poi(n,j)]);
        if(ans==inf)puts("impossible");
        else printf("%d
    ",ans);
    }
    
  • 相关阅读:
    121. Best Time to Buy and Sell Stock
    70. Climbing Stairs
    647. Palindromic Substrings
    609. Find Duplicate File in System
    583. Delete Operation for Two Strings
    556 Next Greater Element III
    553. Optimal Division
    539. Minimum Time Difference
    537. Complex Number Multiplication
    227. Basic Calculator II
  • 原文地址:https://www.cnblogs.com/Xing-Ling/p/11652585.html
Copyright © 2011-2022 走看看