poj 3159 Candies
差束约分
有人将这题归为最短路的中等题,所以做一下,但是发现其实是裸的差束约分
题意:n个人,m个信息,每行的信息是3个数字,A,B,C,表示B比A多出来的糖果不超过C个,问你,n号人最多比1号人多几个糖果
m行信息,所以得到m个不等式 : XB - XA <= C , 所有不等式加起来就是一个差束约分系统
对应最短路模型,一开始是 d[v] >= d[u]+w (有向边u--->v) , 在进行完最短路后则变为 d[v] <= d[u] + w ,转化为 d[v] - d[u] <= w
这个和上面的 XB - XA <= C 是相同的模式 , 因此建图的时候有向边应该是 A----->B , 边权为C
所以我们是要求 max( Xn - X1) , 可知是 Xn - X1 <= res 令其取最大值,就是 Xn - X1 = res
所以以1为源点,n为汇点,运行一次最段落即可
没有负权,所以spfa和dij都可以
另外这题长见识了,用spfa+queue是会超时的,用spfa+stack则500ms。另外写成spfa的dfs搜索式也是会超时的,所以这也验证了spfa很不稳定
同样的,朴素的dij是会超时的,要用堆优化,即优先队列版本的dij
下面只给出spfa+stack(迭代版本,模拟dfs,但是dfs居然超时)的代码
#include <cstdio> #include <cstring> #include <stack> #include <vector> using namespace std; #define N 30010 #define M 150010 #define INF 0x3f3f3f3f int head[N]; struct edge { int u,v,w,next; }e[M]; int d[N]; int n,tot; bool ins[N]; void add(int u ,int v ,int w) { e[tot].u = u; e[tot].v = v; e[tot].w = w; e[tot].next = head[u]; head[u] = tot++; } void spfa(int s, int t) { stack<int>sta; memset(d,0x3f,sizeof(d)); memset(ins,false,sizeof(ins)); while(!sta.empty()) sta.pop(); d[s] = 0; sta.push(s); ins[s] = true; while(!sta.empty()) { int u,v,w; u = sta.top(); sta.pop(); ins[u] = false; for(int k=head[u]; k!=-1; k=e[k].next) { v = e[k].v; w = e[k].w; if(d[u]+w < d[v]) { d[v] = d[u] + w; if(!ins[v]) { sta.push(v); ins[v] = true; } } } } printf("%d\n",d[t]); } int main() { int n,m; scanf("%d%d",&n,&m); //while(scanf("%d%d",&n,&m)!=EOF) //{ tot = 0; memset(head,-1,sizeof(head)); for(int i=0; i<m; i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); add(u,v,w); } spfa(1,n); //} return 0; }