XJOI xtx的旅行(状压+spfa)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了XJOI xtx的旅行(状压+spfa)相关的知识,希望对你有一定的参考价值。
这题是一道状压加spfa,考试的时候我非常naive地写了一个复杂度为O(4^p)*O(n+m)的暴力,因为复杂度上界比较松,就卡着评测机水过了.(2000+ms)
但是这题仅仅那样做非常不科学,非常慢,也可以被卡掉时间.
于是,我请教了旁边的cxt(%%%%)
cxt对我说到达一个点以及一个状态后,可以分开买物品和走路,这非常有道理,因为买物品和走路是互不影响的,这样上界就是O(2^p)*O(n+m)
于是,我贯彻cxt的思想,写了一个自认为很高妙的程序,跑了500ms+.
但是,cxt看了我的程序,认为我还是很不对,因为可以一个一个买物品,而不需要枚举子集,因为存下了买物品的状态后,一个一个买物品时相互之间也已经互不影响了.
于是,我又写了一个100ms+的程序
以下依次是三个程序:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll INF=1e16,N=210,MAX_ZT=1050,M=2010,P=11; int n,m,p,s,x,y,z,hh,max_zt,k,co[1034],b[M],c[M],d[M],fi[N],ne[M],have[N],price[N][P]; ll f[N][MAX_ZT]; bool bb[N][MAX_ZT]; struct dd{int ind,zt;dd(int x,int y):ind(x),zt(y){}}; queue<dd>q; inline void add(int x,int y,int z,int hh){ b[++k]=y; c[k]=z; d[k]=hh; ne[k]=fi[x]; fi[x]=k; } inline int count(int x){ if (co[x]) return co[x]; int res=0,yx=x; for ( ; x; x>>=1) if (x&1) ++res; return co[yx]=res; } inline int calc(int x,int y){ int gi=1,res=0; for (int i=0; i<p; i++){ if (y&gi) res+=price[x][i+1]; gi<<=1; } return res; } void spfa(){ for (int i=1; i<=n; i++) for (int j=0; j<max_zt; j++) f[i][j]=INF; for (int l=have[s]; l>=0; l=(l>0?have[s]&(l-1):-1)) f[s][l]=calc(s,l),q.push(dd(s,l)); while (!q.empty()){ int x=q.front().ind; int k=q.front().zt; q.pop(); bb[x][k]=0; for (int j=fi[x]; j; j=ne[j]){ int cost_on_road=c[j]+count(k)*d[j]; for (int l=have[b[j]]; l>=0; l=(l>0?have[b[j]]&(l-1):-1)) if ((!(k&l))&&f[x][k]+cost_on_road+calc(b[j],l)<f[b[j]][k|l]){ f[b[j]][k|l]=f[x][k]+cost_on_road+calc(b[j],l); if (!bb[b[j]][k|l]) q.push(dd(b[j],k|l)),bb[b[j]][k|l]=1; } } } } int main(){ scanf("%d%d%d%d",&n,&m,&p,&s); for (int i=1; i<=p; i++){ scanf("%d",&k); for (int j=1; j<=k; j++){ scanf("%d%d",&x,&y); if (!price[x][i]||y<price[x][i]) price[x][i]=y; have[x]|=1<<(i-1); } } for (int i=1; i<=m; i++) scanf("%d%d%d%d",&x,&y,&z,&hh),add(x,y,z,hh); max_zt=(1<<p); spfa(); printf("%lld",f[s][max_zt-1]); }
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll INF=1e16,N=210,MAX_ZT=1050,M=2010,P=11; int n,m,p,s,x,y,z,hh,max_zt,k,co[1034],b[M],c[M],d[M],fi[N],ne[M],have[N],price[N][P],ca[N][MAX_ZT]; ll f[N][MAX_ZT]; bool bb[N][MAX_ZT]; struct dd{int ind,zt;dd(int x,int y):ind(x),zt(y){}}; queue<dd>q; inline void add(int x,int y,int z,int hh){ b[++k]=y; c[k]=z; d[k]=hh; ne[k]=fi[x]; fi[x]=k; } inline int calc(int x,int y){ if (ca[x][y]) return ca[x][y]; int gi=1,res=0; for (int i=0; i<p; i++){ if (y&gi) res+=price[x][i+1]; gi<<=1; } return ca[x][y]=res; } void spfa(){ for (int i=1; i<=n; i++) for (int j=0; j<max_zt; j++) f[i][j]=INF; f[s][0]=0; q.push(dd(s,0)); while (!q.empty()){ int x=q.front().ind; int k=q.front().zt; q.pop(); bb[x][k]=0; for (int j=have[x]; j; j=have[x]&(j-1)) if (!(k&j)&&f[x][k|j]>f[x][k]+calc(x,j)){ f[x][k|j]=f[x][k]+calc(x,j); if (!bb[x][k|j]) q.push(dd(x,k|j)),bb[x][k|j]=1; } for (int j=fi[x]; j; j=ne[j]){ int cost_on_road=c[j]+co[k]*d[j]; if (f[b[j]][k]>f[x][k]+cost_on_road){ f[b[j]][k]=f[x][k]+cost_on_road; if (!bb[b[j]][k]) q.push(dd(b[j],k)),bb[b[j]][k]=1; } } } } int main(){ scanf("%d%d%d%d",&n,&m,&p,&s); for (int i=1; i<=p; i++){ scanf("%d",&k); for (int j=1; j<=k; j++){ scanf("%d%d",&x,&y); if (!price[x][i]||y<price[x][i]) price[x][i]=y; have[x]|=1<<(i-1); } } for (int i=1; i<=m; i++) scanf("%d%d%d%d",&x,&y,&z,&hh),add(x,y,z,hh); max_zt=(1<<p); co[0]=0; for (int i=1; i<max_zt; i++) co[i]=co[i&(i-1)]+1; spfa(); printf("%lld",f[s][max_zt-1]); }
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll INF=1e16,N=210,MAX_ZT=1050,M=2010,P=11; int n,m,p,s,x,y,z,hh,max_zt,k,co[1034],b[M],c[M],d[M],fi[N],ne[M]; ll f[N][MAX_ZT]; bool bb[N][MAX_ZT]; struct dd{int ind,zt;dd(int x,int y):ind(x),zt(y){}}; vector<dd>price[N]; queue<dd>q; inline void add(int x,int y,int z,int hh){ b[++k]=y; c[k]=z; d[k]=hh; ne[k]=fi[x]; fi[x]=k; } void spfa(){ for (int i=1; i<=n; i++) for (int j=0; j<max_zt; j++) f[i][j]=INF; f[s][0]=0; q.push(dd(s,0)); while (!q.empty()){ int x=q.front().ind; int k=q.front().zt; q.pop(); bb[x][k]=0; for (vector<dd>::iterator it=price[x].begin(); it!=price[x].end(); it++){ dd t=*it; int l=1<<t.ind-1; if (!(k&l)&&f[x][k|l]>f[x][k]+t.zt){ f[x][k|l]=f[x][k]+t.zt; if (!bb[x][k|l]) q.push(dd(x,k|l)),bb[x][k|l]=1; } } for (int j=fi[x]; j; j=ne[j]){ int cost_on_road=c[j]+co[k]*d[j]; if (f[b[j]][k]>f[x][k]+cost_on_road){ f[b[j]][k]=f[x][k]+cost_on_road; if (!bb[b[j]][k]) q.push(dd(b[j],k)),bb[b[j]][k]=1; } } } } int main(){ scanf("%d%d%d%d",&n,&m,&p,&s); for (int i=1; i<=p; i++){ scanf("%d",&k); for (int j=1; j<=k; j++){ scanf("%d%d",&x,&y); price[x].push_back(dd(i,y)); } } for (int i=1; i<=m; i++) scanf("%d%d%d%d",&x,&y,&z,&hh),add(x,y,z,hh); max_zt=(1<<p); co[0]=0; for (int i=1; i<max_zt; i++) co[i]=co[i&(i-1)]+1; spfa(); printf("%lld",f[s][max_zt-1]); }
以上是关于XJOI xtx的旅行(状压+spfa)的主要内容,如果未能解决你的问题,请参考以下文章