[ZJOI2006]物流运输

link

一道典型的早期OI题目:数据范围小,技巧性不强,代码简短,考察的知识点比较初级,但客观上来说仍然具有一定的思维难度。

对于这道题来说,读懂题是关键。题目是说假如给定一张无向图,图上一些节点在某个时间段内无法使用,且知道每次改变路径都会付出一定代价,询问总花费最小值。

显然可以考虑DP。用f[i]代表第一天到第i天的最少花费,很显然这个状态设计具有无后效性,于是就可以考虑枚举决策。每个决策实际上对应的是一段时间内要求走同一条路径的最小花费,跑最短路即可。由于数据范围很小可以轻松过掉。

#include<cstdio>
#include<queue>
#include<cstring>
//#define zczc
#define int long long
using namespace std;
const int N=25;
const int M=110;
inline void read(int &wh){
    wh=0;int f=1;char w=getchar();
    while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
    while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();}
    wh*=f;return;
}
inline int min(int s1,int s2){
	return s1<s2?s1:s2;
}

int m,n,es,cost,f[M],sum[N][M];

struct edge{
	int t,v,next;
}e[N*N*2];
int head[N],esum;
inline void add(int fr,int to,int val){
	e[++esum]=(edge){to,val,head[fr]};head[fr]=esum;
}

int cnt,a[N],dis[N];
struct node{
	int id,dis;
};
inline bool operator <(node s1,node s2){
	return s2.dis<s1.dis;
}
priority_queue<node>q;
int c(int l,int r){
	memset(dis,0x3f,sizeof(dis));
	q.push((node){1,dis[1]=0});
	while(!q.empty()){
		node now=q.top();q.pop();
		int wh=now.id,nd=now.dis;
		if(sum[wh][r]-sum[wh][l-1]>0||nd>dis[wh])continue;
		for(int i=head[wh],th;i;i=e[i].next){
			if(dis[wh]+e[i].v<dis[th=e[i].t]){
				dis[th]=dis[wh]+e[i].v;
				q.push((node){th,dis[th]});
			}
		}
	}
	return min(dis[m],1e9);
}

signed main(){
	
	#ifdef zczc
	freopen("in.txt","r",stdin);
	#endif
	
	int s1,s2,s3;
	read(n);read(m);read(cost);read(es);
	while(es--){
		read(s1);read(s2);read(s3);
		add(s1,s2,s3);add(s2,s1,s3);
	}
	read(es);
	while(es--){
		read(s1);read(s2);read(s3);
		for(int i=s2;i<=s3;i++)sum[s1][i]=1;
	}
	for(int i=1;i<=m;i++)
		for(int j=1;j<=n;j++)
			sum[i][j]+=sum[i][j-1];
	memset(f,0x3f,sizeof(f));
	f[0]=-cost;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=i;j++)
			f[i]=min(f[i],f[j-1]+c(j,i)*(i-j+1)+cost);
	printf("%lld\n",f[n]);
	
	return 0;
}
posted @ 2022-05-19 22:16  Feyn618  阅读(18)  评论(0编辑  收藏  举报