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;
}
``