bzoj1003 物流运输trans

DP+SPFA

题目大意:给定一个无向图,运输n天,其中有些天有些点不能走,更换路线代价为k,求代价总和

首先令cost[i][j]为第i天到第j天都走同一路线的最小花销 这个用SPFA预处理

然后就是动规的问题了 令f[i]为1~i天的最小花销

则f[i]=min{ f[j]+cost[j+1][i]+k } ( 0<=j<i )

注意m和n别写反

乘天数之前要特判是不是正无穷

我自己的代码:

  

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
long long first[201];
struct node
{
	long long to;
	long long next;
	long long len;
};
node bian[40000];
long long cost[201][201];
long long n,m,k,d,e;
long long size;
bool used[205][205];
bool sta[201];
bool exist[205];
long long dis[205];
long long p[400001];
long long dp[201];

long long read()
{
    long long k=0,f=1;
    char c=getchar();
    while(c>'9'||c<'0') {if(c=='-') f=-1; c=getchar();}
    while(c>='0'&&c<='9') {k=k*10+(c-'0'); c=getchar();}
    return k*f;
}
void inser(long long a,long long b,long long c)
{
	size++;
	bian[size].to=b;
	bian[size].len=c;
	bian[size].next=first[a];
	first[a]=size;
}
long long spfa()
{
	long long head=0;
	memset(sta,0,sizeof(sta));
	long long tail=1;
	p[tail]=1;
	dis[1]=0;
	sta[1]=1;
	long long u,i,dd;
	while(head^tail)
	{
		head++;
		u=p[head];
		sta[u]=0;
		for(i=first[u];i;i=bian[i].next)
		{
			dd=bian[i].to;
			if(!exist[dd] &&dis[dd]>dis[u]+bian[i].len)
			  {
			  	dis[dd]=dis[u]+bian[i].len;
			  	if(!sta[dd])
			  	  {
			  	  	sta[dd]=1;
			  	  	tail++;
			  	  	p[tail]=dd;
					}
			  }
		}	
	}
	return dis[m];
}



int main()
{
	freopen("lx.in","r",stdin);
	freopen("lx.out","w",stdout);
	n=read();
	m=read();
	k=read();
	e=read();
	long long i,j,s,t,u;
	
	for(i=1;i<=e;i++)
	  {
	  	s=read();
	  	t=read();
		j=read();
	  	inser(s,t,j);
	  	inser(t,s,j);
	  }
	d=read();
	for(i=1;i<=d;i++)
	  {
	  	u=read();
	  	s=read();
	  	t=read();
	  	for(j=s;j<=t;j++)
	  	  used[j][u]=1;
	  }
	
	for(i=1;i<=n;i++)
	  {
	  	for(u=1;u<=m;u++) exist[u]=0;
	  	for(j=i;j<=n;j++)
	  	  {
	  	     for(u=1;u<=m;u++)
			   if(used[j][u]) 	exist[u]=1;
			 for(u=1;u<=m;u++)  dis[u]=1000000000;  
		     cost[i][j]=spfa();
		  }
	  }
	
//    for(i=1;i<=n;i++) dp[i]=100000000;
	
	for(i=1;i<=n;i++)
	  {
	  	dp[i]=cost[1][i]*i;
	  	for(j=1;j<i;j++)
	  	  {
	  	  	if(cost[j+1][i]<1000000000)
	  	  	dp[i]=min(dp[i],dp[j]+cost[j+1][i]*(i-j)+k);
			}
	  }
	cout<<dp[n];
	return 0;
} 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值