POJ 1062 昂贵的聘礼 (约束最短路)
- 题意: 有向图,每个点代表一个物品(有价格,级别),边代表从当前点转移到目的点的价格,问买到1点的最小价格,路径上点的级别差不能超过m
- 思路: 不考虑级别则通过
d[y] > d[x]+cost[x][y]-a[x]+a[y]
价格转移,正向存边求1到所有点的最短路即可.
考虑级别差,当级别差为0时代表没有级别差,然后需要枚举最大级别跑n边最短路lv-lev[u]>m || lev[u]>lv || abs(lev[u]-lev[s])>m
表示不符合当前约束经过观察POJ讨论版的上的数据,感觉实际可以表示为一个DAG,然后通过DP来做
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <stdlib.h>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
#define ll long long
#define FOR(i,l,r) for(int i = l ; i <= r ;++i )
#define inf 1<<30
#define EPS (1e-9)
#define ALL(T) T.begin(),T.end()
#define lson(i) i<<1
#define rson(i) (i<<1|1)
using namespace std;
typedef pair<int,int> pii;
const int maxn = 110,maxm =10110;
struct Edge{
int to,next,cost;
}edge[maxm];
int head[maxn],tot;
int d[maxn],v[maxn];
int a[maxn],lev[maxn];
int n,m,s;
void addEdge(int u,int v,int w){
edge[++tot].to = v;
edge[tot].cost = w;
edge[tot].next = head[u];
head[u] = tot;
}
void init(){
memset(head,0,sizeof(head));
tot = 0;
}
int spfa(int s,int lv){
queue<int> q;
FOR(i,1,n){
v[i] = 0;
d[i]=a[i]+a[s];
}
d[s]-=a[s];
q.push(s);
while(q.size()){
int x= q.front(); q.pop();
v[x] = 0;
for(int i=head[x];i;i=edge[i].next){
int y = edge[i].to;
if(lv-lev[y]>m || lev[y]>lv || abs(lev[y]-lev[s])>m)
continue;
int z = edge[i].cost;
if( d[y] > d[x]+z-a[x]+a[y]){
d[y] = d[x]+z-a[x]+a[y];
if(v[y]==0){
q.push(y);
v[y] = 1;
}
}
}
}
int mi = inf;
FOR(i,1,n) mi = min(mi,d[i]);
return mi;
}
int dij(int s,int lv){
priority_queue<pii,vector<pii>,greater<pii> > que;
FOR(i,1,n){
d[i]=a[i]+a[s];
}
d[s]-=a[s];
que.push(pii(d[s],s));
while(!que.empty()){
pii p = que.top(); que.pop();
int v = p.second;
if(d[v]<p.first) continue;
for(int i=head[v];i;i=edge[i].next){
int u = edge[i].to;
if(lv-lev[u]>m || lev[u]>lv || abs(lev[u]-lev[s])>m)
continue;
if( d[u] > d[v]+edge[i].cost-a[v]+a[u]){
d[u] = d[v]+edge[i].cost-a[v]+a[u];
que.push(pii(d[u],u));
}
}
}
int mi = inf;
FOR(i,1,n) mi = min(mi,d[i]);
return mi;
}
int main(){
while(cin >> m >> n){
if(m==0) m = 110;
int k,fr,weight;
init();
FOR(i,1,n){
cin >> a[i] >> lev[i] >>k;
FOR(j,1,k){
cin >>fr >> weight;
addEdge(i,fr,weight);
}
}
int ans = inf;
FOR(i,1,n){
if((lev[i]-lev[1])<=m)
// ans = min(ans,spfa(1,lev[i]));
ans = min(ans,dij(1,lev[i]));
}
cout << ans <<endl;
}
return 0;
}
spfa和dijkstra都是47ms,没什么差别