csp练习
21次
04-食材运输
思路:
首先看30%的部分。
检查点数量与运输车数量相同,并且保证图是一条链。
把检查点设置在每辆运输车的出发点。
每辆食材运输车的路径就是,需要这种食材的酒店中,从最左边的那个出发,到最右边的那个结束。
路径中的最长等待时间就是路径的长度。
所以答案是所有路径长度中的最大值。
70%部分。
检查点数量与运输车数量相同。
与30%的相同,把检查点设置在每辆运输车的出发点,无需考虑检查点位置。
若出发点为x,我们将需要运送该食材的所有点与x相连,可以得到一棵树,
我们可以发现,除了最后到达的节点与x之间的边(只经过一次),所有的边都会被经过两次。
假设这棵树上所有路径的总长为DIS,最后一个到达的点为y,那么这次运送中的最长等待时间就是2DIS-dis[y]
而对于最小的最大等待时间,就是2DIS-max_dis
于是枚举每辆运输车,枚举每个点为这辆运输车的出发点x,
然后以x为出发点进行搜索,求出DIS和max_dis。
统计枚举每个出发点中得到的2DIS-max_dis的最小值ans,
然后再统计每辆运输车中最长等待时间的最大值ANS。
(说好的70分呢,似乎把样例1特判一下还有5分)
下面是参考代码,注释有点乱。。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=105;
int num,to[maxn<<1],nxt[maxn<<1],w[maxn<<1],last[maxn],dis[maxn],DIS,Max_dis;
int need[maxn][12];
void clear(){
num=0;
memset(last,-1,sizeof(last));
}
void insert(int x,int y,int z){
to[++num]=y;
nxt[num]=last[x];
last[x]=num;
w[num]=z;
}
bool dfs(int x,int pre,int fd){
int i,y;
bool re=false;
if (need[x][fd]) re=true;
//x需要运送食材fd,标记边(pre,x)
for (i=last[x];i!=-1;i=nxt[i]){
y=to[i];
if (y==pre) continue;//不走回头路
dis[y]=dis[x]+w[i];//记录y与根节点的距离
if (dfs(y,x,fd)) {
DIS+=w[i];
//将标记路径加入总路径
Max_dis=max(Max_dis,dis[y]);
//记录标记路径上距离根节点最远的节点距离
re=true;
//由于x的子节点需要运送,标记边(pre,x)
}
}
return re;
}
int main(){
int n,m,k,i,j,x,y,z;
int now,ans,ANS;
scanf("%d%d%d",&n,&m,&k);
for (i=1;i<=n;i++){
for (j=1;j<=k;j++){
scanf("%d",&need[i][j]);
}
}
clear();
for (i=1;i<n;i++){
scanf("%d%d%d",&x,&y,&z);
insert(x,y,z);
insert(y,x,z);
}//建图
ANS=0;
for (i=1;i<=k;i++){//枚举每种每辆食材运输车
ans=-1;//用于统计枚举出发点位置过程中,最大等待时间的最小值
for (j=1;j<=n;j++){//枚举出发点位置
dis[j]=0;
DIS=0;
Max_dis=0;
dfs(j,j,i);
/*
dfs作用:以j为根节点,
计算所有需要运送食材i的节点与j连接后,得到的树中所有边之和DIS,
并记录所有需要运送食材i的节点距离根节点j的路径的最大值Max_dis
*/
now=2*DIS-Max_dis;//得到的最小的最大等待时间
if (ans==-1 || now<ans) ans=now;
}
if (ans>ANS) ANS=ans;//ANS用于记录所有食材运输车中最大等待时间的最大值
}
printf("%d\n",ANS);
return 0;
}