pat1018

来源:互联网 发布:山东冶金设计院知乎 编辑:程序博客网 时间:2024/06/10 16:41

个人认为这题在pat里面算是比较难了,主要是有2点,1,可能很多同学理解不了为什么车送出去了还得送回去,现在把问题简化,就给你一串数,a[1],a[2],a[3],,,,a[n],假设为了让这些数都变成一个k,我需要从a[0]拿出一些数,从左往右送,那么我最少需要拿出多少,才能保证后面的n个数都能变成k。2本题自己想了2种方法,第一是自己想出来的,记录所有最短路的路径,然后倒着搜回去,搜到起点做一次比较,找出最优的,另外有一个方法是dij找出最短路后,利用一个比较强的剪枝直接顺着搜。总得来说,这2个搜索都不是很好写,而且本题条件要求很复杂,首先是最短路,多条最短路的情况下,选择拿出最少,拿出最少的情况下选择拿回去最少。

下面说明一下第一个问题,假设这么一串数:

 3  6 2 9 8       k=5

那么到a[1],是少了2辆,记为-2,到a[2],多了一辆(6-5=1),那么总体来说少了1辆,记为-1,依次类推,分别有,-2,-1,-4,0,3 你会发现这串数最难满足的是-4,那么你要在起点拿出4,至于终点还能拿回多少,其实就是到最后你发现就算你不拿,还能多出3辆,但是你不能不拿,你要是不拿,就算你后面多出再多,前面也无法满足,因为他是从前往后送的。你拿了4辆,就多出7辆。所以最终拿回几辆,是最后这个数加上你拿出来的数。

附代码如下:

倒搜记录路径版:

#include<stdio.h>#include<string.h>#define inf 0x7FFFFFint a[501];int dis[501];int map[501][501];int Min(int x,int y){return x<y?x:y;}int mark[501];int pre[501][501];int cm,n,sp,m;int ans[501];int tmp[501];int vi[501];int in,out;int len;void dfs(int x,int dep){int i;if(x==0){int cc=0;int cur1,cur2;cur1=inf;for(i=dep-1;i>=0;i--){cc+=a[tmp[i]]-cm/2;if(cc<cur1)cur1=cc;}if(cur1>0)cur1=0;cur2=-cur1+cc;if(cur1>in||( (cur1==in)&&(cur2<out) ) ) {in=cur1;out=cur2;len=dep;for(i=dep-1;i>=1;i--)ans[i]=tmp[dep-i];}}for(i=1;i<=pre[x][0];i++){int node=pre[x][i];if(vi[node]==0){vi[node]=1;tmp[dep+1]=node;dfs(node,dep+1);vi[node]=0;}}return ;}int main(){int i,j;while(scanf("%d%d%d%d",&cm,&n,&sp,&m)!=EOF){for(i=1;i<=n;i++)scanf("%d",a+i);a[0]=0;for(i=0;i<=n;i++)for(j=0;j<=n;j++)map[i][j]=map[j][i]=inf;for(i=1;i<=m;i++){int a,b,x;scanf("%d%d%d",&a,&b,&x);map[a][b]=map[b][a]=x;}for(i=1;i<=n;i++){dis[i]=map[i][0];mark[i]=0;if(dis[i]!=inf){pre[i][0]=1;pre[i][1]=0;}}while(1){int min=inf;int dd=-1;for(i=1;i<=n;i++)if(dis[i]<min&&mark[i]==0){min=dis[i];dd=i;}mark[dd]=1;for(i=1;i<=n;i++){if(mark[i]==0){if(dis[dd]+map[i][dd]<dis[i]){dis[i]=dis[dd]+map[i][dd];pre[i][0]=1;pre[i][1]=dd;}else if(dis[dd]+map[i][dd]==dis[i]){pre[i][0]++;pre[i][pre[i][0]]=dd;}}}if(dd==sp)break;}memset(vi,0,sizeof(vi));tmp[0]=sp;in=-inf;out=inf;dfs(sp,0);int aans=0;printf("%d ",-in);printf("0->");for(i=1;i<len;i++)printf("%d->",ans[i]);printf("%d %d\n",sp,out);}}


 


顺搜剪枝版:

#include<stdio.h>#include<stdio.h>#include<string.h>#define inf 0x7FFFFFint a[501];int dis[501];int map[501][501];int res1,res2;int mark[501];int cm,n,sp,m;int ans[501];int tmp[501];int vi[501];int nowdep;void dfs(int x,int d,int dep){if(dis[x]<d)return ;int i ;if(x==sp&&d==dis[sp]){int cc=0;int cur1=inf;int cur2;for(i=1;i<=dep;i++){cc+=a[tmp[i]]-cm/2;if(cc<cur1)cur1=cc;}if(cur1>0)cur1=0;cur2=-cur1+cc;if(cur1>res1||(  (cur1==res1)&&(res2>cur2) ) ){res1=cur1;res2=cur2;for(i=1;i<=dep;i++)ans[i]=tmp[i];nowdep=dep;}return ;}for(i=1;i<=n;i++)if(vi[i]==0&&map[i][x]!=inf){vi[i]=1;tmp[dep+1]=i;dfs(i,d+map[i][x],dep+1);vi[i]=0;}return ;}int main(){int i,j;while(scanf("%d%d%d%d",&cm,&n,&sp,&m)!=EOF){for(i=1;i<=n;i++)scanf("%d",a+i);for(i=0;i<=n;i++)for(j=0;j<=n;j++)map[i][j]=map[j][i]=inf;for(i=1;i<=m;i++){int a,b,x;scanf("%d%d%d",&a,&b,&x);map[a][b]=map[b][a]=x;}for(i=1;i<=n;i++){dis[i]=map[i][0];mark[i]=0;}mark[0]=1;while(1){int min=inf;int dd=-1;for(i=1;i<=n;i++)if(dis[i]<min&&mark[i]==0){min=dis[i];dd=i;}mark[dd]=1;for(i=1;i<=n;i++){if(mark[i]==0&&dis[dd]+map[i][dd]<dis[i])dis[i]=dis[dd]+map[i][dd];}if(dd==sp)break;}res1=-inf;res2=inf;dfs(0,0,0);printf("%d ",-res1);printf("0->");for(i=1;i<nowdep;i++)printf("%d->",ans[i]);printf("%d %d\n",ans[nowdep],res2);}return 0;}