b_vj_Paid Roads(枚举边+点集+有向环处理)

从城市Ai到城市Bi,有两种方式支付旅行费用:

  • 在城市Ci提前支付pi(Ci可能不等于Ai);
  • 出差后在城市Bi支付,花费Ri。

思路f[i][j]表示到达点i,且已经遍历过的点状态为j时的最小花费
当E[i]=u,v时,f[v][j]=min(f[v][j|1<<u], f[u][j]+cost)(cost=p/r)

注:由于图中有有向环,而去过某些点可能会使下一步的花费变得更小,所以我只要迭代一次找到了更小的值find_min,我就继续迭代

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=15, inf=0x3f3f3f3f;
int n,m,M,f[N][1<<N],find_min=1; 
struct node {
    int a,b,c,p,r;
}E[N];
int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin>>n>>m; for (int i=0; i<m; i++) cin>>E[i].a>>E[i].b>>E[i].c>>E[i].p>>E[i].r, E[i].a--, E[i].b--, E[i].c--;
    for (int i=0; i<n; i++) fill(f[i],f[i]+(1<<N),inf);
    f[0][0]=0, M=1<<n;
    
    while (find_min) {
        find_min=0;
        for (int i=0; i<m; i++)
        for (int j=0; j<M; j++) {
            int a=E[i].a, b=E[i].b, c=E[i].c, p=E[i].p, r=E[i].r, &t=f[b][j|1<<a], last=t;
            if (j&(1<<c)) t=min(t, f[a][j]+p); //j中有E[i].c
            else t=min(t, f[a][j]+r); //j中没有E[i].c
            if (t<last) find_min=1;
        }
    }
    int ans=inf;
    for (int j=0; j<M; j++) ans=min(ans, f[n-1][j]);
    if (ans==inf) cout<<"impossible";
    else cout<<ans;
    return 0;
}
``
原文地址:https://www.cnblogs.com/wdt1/p/13940290.html