• 【[ZJOI2006]物流运输】


    一直不会做,觉得这是一道神题

    于是万般无奈下去借鉴抄了一下题解

    发现这就是一道套路题

    我们用(dp[i])表示前(i)天的最小总花费,于是我们就可以用一个常规的老套路来做了

    那就是枚举断点

    我们如果可以预处理出一个数组(dis[i][j])表示在第(i)天到第(j)天的最短路的话,方程是不是就很好写了

    (dp[i]=min(dp[j]+k+dis[j+1][i]*(i-j)))

    但是我们这个数组怎么预处理呢

    瞎跑最短路就可以了

    反正数据范围这么小,基本什么算法都能过去了,对于(dijkstra),把那些不能走的点标记成已经找到了最短路,让这些点没有办法去做松弛操作就好了

    这种断点类dp的题还是不少的,比如说经典的山区建小学,在比如说那道统计单词个数都是比较套路的枚举断点类dp,这种dp的复杂度一般来说是(O(n^2))的,枚举断点的时候也非常无脑,所以对于这种dp,应该尽量保证见到就能A掉

    代码

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    #include<bitset>
    #define mp make_pair
    #define re register
    #define maxn 101
    #define inf 999999999
    #define LL long long
    using namespace std;
    struct GG
    {
    	int v,nxt,w;
    }e[10001];
    LL n,m,k,E,Q,num;
    typedef pair<LL,int> pii;
    priority_queue<pii,vector<pii>,greater<pii> > q;
    LL d[maxn],head[maxn];
    bitset<maxn> f;
    LL dp[101];
    int a[101][101],tot[101];
    LL dis[101][101];
    inline LL read()
    {
    	char c=getchar();
    	LL x=0;
    	while(c<'0'||c>'9') c=getchar();
    	while(c>='0'&&c<='9')
    	  x=(x<<3)+(x<<1)+c-48,c=getchar();
    	return x;
    }
    inline void add_edge(int x,int y,int z)
    {
    	e[++num].v=y;
    	e[num].nxt=head[x];
    	e[num].w=z;
    	head[x]=num;
    }
    inline LL dijkstra(int beg,int enn)
    {
    	for(re int i=1;i<=m;i++) 
    		d[i]=inf,f[i]=0;
    	for(re int i=beg;i<=enn;i++)
    	{
    		for(re int j=1;j<=tot[i];j++)
    			f[a[i][j]]=1;
    	}
    	d[1]=0;
    	q.push(mp(0,1));
    	while(!q.empty())
    	{
    		int k=q.top().second;
    		q.pop();
    		if(f[k]) continue;
    		f[k]=1;
    		for(re int i=head[k];i;i=e[i].nxt)
    		if(d[e[i].v]>d[k]+e[i].w)
    		{
    			d[e[i].v]=d[k]+e[i].w;
    			q.push(mp(d[e[i].v],e[i].v));
    		}
    	}
    	return d[m];
    }
    int main()
    {
    	n=read();
    	m=read();
    	k=read();
    	E=read();
    	LL x,y,z;
    	for(re int i=1;i<=E;i++)
    	{
    		x=read();
    		y=read();
    		z=read();
    		add_edge(x,y,z);
    		add_edge(y,x,z);
    	}
    	Q=read();
    	while(Q--)
    	{
    		z=read();
    		x=read();
    		y=read();
    		for(re int i=x;i<=y;i++)
    			a[i][++tot[i]]=z;
    	}
    	for(re int i=1;i<=n;i++)
    	for(re int j=i;j<=n;j++)
    		dis[i][j]=dijkstra(i,j);
    	for(re int i=1;i<=n;i++)
    	{
    		dp[i]=i*dis[1][i];
    		for(re int j=1;j<i;j++)
    		dp[i]=min(dp[i],dp[j]+dis[j+1][i]*(i-j)+k);
    	}	
    	cout<<dp[n]<<endl;
    	return 0;
    }
    
  • 相关阅读:
    LeetCode 25 Reverse Nodes in k-Group
    圆桌派:家世背景对人的影响有多大
    BibTex 学习笔记
    R parallel包实现多线程1
    IIS学习笔记
    高效完成R代码
    圆桌派 :我们,朋友一生一起走
    高文欣个人简介
    R语言函数话学习笔记5
    git学习笔记1
  • 原文地址:https://www.cnblogs.com/asuldb/p/10207823.html
Copyright © 2020-2023  润新知