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
",ANS);
	return 0; 
}
原文地址:https://www.cnblogs.com/lsykk/p/15230722.html