[csp-201809-4]再卖菜 差分约束or记忆化搜索
先更新第一个做法:差分约束
转化成最长路,求出的每一个解是满足差分方程的最小值
spfa求最短路
对于边(x->y) 有:
1 if(dis[y] > dis[x] + a[i].d) dis[y]=dis[x]+a[i].d;
dis[y]的初始值为INF,dis[y]会是满足所有约束条件之中所有可能的值之中最大的(更新到最大的就不会再更新了)。
贴一个简略的证明:
同理,最长路求出来的是所有可能解之中最大的。
这题是字典序最小,那么我们要转化成最长路来求,求到的每个s[i]都是可能的值中最小的一个。注意,菜价要是正整数(>=1)。
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int N=3100; 5 struct node{ 6 int x,y,d,next; 7 }a[2*N]; 8 int n,al,first[N],b[N],s[N]; 9 bool vis[N]; 10 queue<int> q; 11 12 void ins(int x,int y,int d) 13 { 14 al++; 15 a[al].x=x;a[al].y=y;a[al].d=d; 16 a[al].next=first[x];first[x]=al; 17 } 18 19 void build_edge() 20 { 21 al=0; 22 memset(first,0,sizeof(first)); 23 ins(0,2,2*b[1]); 24 ins(2,0,-(2*b[1]+1)); 25 for(int i=2;i<=n-1;i++) 26 { 27 ins(i-2,i+1,3*b[i]); 28 ins(i+1,i-2,-(3*b[i]+2)); 29 } 30 ins(n-2,n,2*b[n]); 31 ins(n,n-2,-(2*b[n]+1)); 32 for(int i=1;i<=n;i++) ins(i-1,i,1); 33 } 34 35 void spfa() 36 { 37 while(!q.empty()) q.pop(); 38 memset(s,0,sizeof(s)); 39 memset(vis,0,sizeof(vis)); 40 s[0]=0;vis[0]=1;q.push(0); 41 while(!q.empty()) 42 { 43 int x=q.front();q.pop(); 44 for(int i=first[x];i;i=a[i].next) 45 { 46 int y=a[i].y; 47 if(s[y]<s[x]+a[i].d) 48 { 49 s[y]=s[x]+a[i].d; 50 if(!vis[y]) 51 { 52 vis[y]=1; 53 q.push(y); 54 } 55 } 56 } 57 vis[x]=0; 58 } 59 } 60 61 int main() 62 { 63 //freopen("a.in","r",stdin); 64 scanf("%d",&n); 65 for(int i=1;i<=n;i++) scanf("%d",&b[i]); 66 build_edge(); 67 spfa(); 68 for(int i=1;i<=n;i++) 69 printf("%d ",s[i]-s[i-1]);printf("\n"); 70 return 0; 71 }