PAT1018. Public Bike Management
阿新 • • 發佈:2019-02-01
從出發點到終點的路徑上的所有節點都要調整為cmax/2,但是隻能在去往終點的時候調整,回來的時候不調整,所以可能既要帶出又要帶回車子。這類題用dfs寫起來都很簡單,例如如下程式碼:
#include<algorithm> #include<deque> #include<cstdio> using namespace std; const int N=503,M=1<<30; int dis[N][N],cmax,n,sp,m,has[N]; bool used[N]; int mlen=M,mout,mback,pre[N]; deque<int>path; void dfs(int k,int len,int out,int back) { if(k) { back+=has[k]-cmax/2; if(back<0) { out-=back; back=0; } } if(k==sp) { if((len<mlen)||(len==mlen)&&(out<mout||(out==mout&&back<mback))) { mlen=len,mout=out,mback=back; path.clear(); path.push_back(k); while(k) path.push_back(k=pre[k]); } return; } for(int i=1;i<=n;++i) if(!used[i]&&dis[k][i]!=M) { pre[i]=k; used[i]=true; dfs(i,len+dis[k][i],out,back); used[i]=false; } } int main() { scanf("%d%d%d%d",&cmax,&n,&sp,&m); for(int i=1;i<=n;++i) scanf("%d",has+i); fill_n(*dis,N*N,M); for(int i=0;i<m;++i) { int a,b,c; scanf("%d%d%d",&a,&b,&c); dis[a][b]=dis[b][a]=c; } used[0]=true; dfs(0,0,0,0); printf("%d %d",mout,path[path.size()-1]); for(int i=path.size()-2;i>=0;--i) printf("->%d",path[i]); printf(" %d\n",mback); return 0; }
但dfs的效率比較低,所以最好用dijkstra演算法,如下面的程式碼,用dijkstra演算法求出圖中的所有單源最短路徑,前驅儲存在pre中,這樣對於任意一個節點x,可以找到原點到x的所有最短路徑,allpath函式就檢查了所有的從原點到目的地的最短路徑,對每條最短路徑用check函式檢視走這條路徑要帶出、帶回的車子數目,把最優路徑儲存在neo中。
#include<algorithm> #include<bitset> #include<iostream> #include<vector> using namespace std; const int N=505,INF=1<<30; int cur[N],cmax,n,src=0,dst,m; //dijkstra只是求出所有的最短路徑來 int dis[N],adj[N][N]; vector<int>pre[N]; void dijkstra(){ bitset<N>used; dis[src]=0; while(true){ int mmin=INF,next=-1; for(int i=0;i<=n;++i) if(!used[i]&&dis[i]<mmin) mmin=dis[next=i]; if(next==-1)break; used.set(next); for(int i=1;i<=n;++i) if(!used[i] && adj[next][i]!=INF){ if(dis[i]>dis[next]+adj[next][i]){ dis[i]=dis[next]+adj[next][i]; pre[i].clear(); pre[i].push_back(next); }else if(dis[i]==dis[next]+adj[next][i]){ pre[i].push_back(next); }//else if.. }//if(!used.. }//while } //check 與 allpath一起工作,檢查終點為dst的所有最短路徑 int out=INF,in=INF; vector<int>neo; void check(vector<int>path){ int _out=0,_in=0,mid=cmax/2; for(auto it=path.rbegin()+1;it!=path.rend();++it){ int c=cur[*it]; _in+=c-mid; if(_in<0)_out-=_in,_in=0; } if(_out<out || _out==out&&_in<in) {neo=path;out=_out;in=_in;} } void allpath(int k){ static vector<int>path; path.push_back(k); if(k!=src) for(auto &x:pre[k]) allpath(x); if(k==src) check(path); path.pop_back(); } int main(){ fill_n(dis,N,INF); fill_n(*adj,N*N,INF); cin>>cmax>>n>>dst>>m; for(int i=1;i<=n;++i)cin>>cur[i]; for(int a,b,c,i=0;i<m;++i){ cin>>a>>b>>c; adj[a][b]=adj[b][a]=c; } dijkstra(); allpath(dst); cout<<out; for(auto it=neo.rbegin();it!=neo.rend();++it) cout<<(it==neo.rbegin()?" ":"->")<<*it; cout<<' '<<in<<endl; }
不論用dfs還是用check檢查路徑,一個要點就是對於路徑上的每個節點,保持”到達該點需要帶出、帶回的車子數“這個性質,這是一個重要的不變式