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,没什么差别

题目连接

原文地址:https://www.cnblogs.com/xxrlz/p/11281088.html