个人认为这题在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 0x7FFFFF
int 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 0x7FFFFF
int 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;
}