poj3411(状态压缩dp,dijkstra最短路)

来源:互联网 发布:js正则表达式实例 编辑:程序博客网 时间:2024/05/22 07:05
/*translation:给出一张图,求节点0到节点n-1花费的最小费用。对于一条边a->b,可以有一下两种不同的付费方式:1.在点c提前预付,但此时必须经过点c,花费为r2.在点b支付,花费为psolution:状态压缩dp+dijkstradp[i][s]:=走到i点时的最优解,且此时走过的点状态为s(包括i)然后根据dijkstra不断松弛即可。note:* 一开始按照普通的DAG状态压缩的做法是错误的,因为这种做法只能使用于有向无环图。而题目中的图可能存在环  所以只能按照dijkstra来进行松弛操作的同时进行状态转移。# 题目中的点可能经过多次,所以枚举状态时的条件注意设置好,见代码注释date:2017.1.20*/#include <iostream>#include <cstring>#include <cstdio>#include <queue>#include <vector>using namespace std;const int maxn = 15;const int INF = 0x3f3f3f3f;int n, m;int dp[maxn][1 << maxn];//dp[i][s]:=走到i点时的最优解,且此时走过的点状态为s(包括i)struct Edge{int to, k, r, p;Edge(int to_, int k_, int r_, int p_):to(to_),k(k_),r(r_),p(p_){}Edge(){}};vector<Edge> edges[maxn];typedef pair<int,int> P;typedef pair<P,int> node;//p.first:节点编号,p.second走过的点的状态  node.second:到目前情况的最优解int dijkstra(int st){priority_queue<node, vector<node>, greater<node> > pq;for(int i = 0; i <= n; i++)fill(dp[i], dp[i] + (1 << n), INF);dp[st][1] = 0;pq.push(node(P(st, 1), 0));while(!pq.empty()) {node x = pq.top();pq.pop();int u = x.first.first, s = x.first.second;if(dp[u][s] < x.second)continue;for(int i = 0; i < edges[u].size(); i++) {Edge e = edges[u][i];int v = e.to;for(int s = 0; s < 1 << n; s++) if(s >> u & 1) { //枚举的状态必须包含u,但可能同时包含v。因为可能重复路径int ns = s | 1 << v;bool flag = false;if(dp[v][ns] > dp[u][s] + e.r) {dp[v][ns] = dp[u][s] + e.r;flag = true;}if(dp[v][ns] > dp[u][s] + e.p && (s >> e.k & 1)) {dp[v][ns] = dp[u][s] + e.p;flag = true;}if(flag) pq.push(node(P(v, ns), dp[v][ns]));}}}int res = INF;for(int s = 0; s < 1 << n; s++)res = min(res, dp[n - 1][s]);return res;}int main(){//freopen("in.txt", "r", stdin);    while(~scanf("%d%d", &n, &m)) {for(int i = 0; i < maxn; i++)edges[i].clear();int a, b, c, p, r;//p是预付,r是现付for(int i = 0; i < m; i++){scanf("%d%d%d%d%d", &a, &b, &c, &p, &r);a--;b--;c--;edges[a].push_back(Edge(b, c, r, p));}int ans = dijkstra(0);if(ans >= INF)printf("impossible\n");elseprintf("%d\n", ans);    }    return 0;}

0 0
原创粉丝点击