题目:
题解:
枚举i、j,表示时间i到时间j的方案不变动。
f[j]表示前j时间的最少费用。
tt表示i到j方案不变动的最少费用。
k是变动一次需要的军粮数。
f[j]:=min(f[j],f[i]+tt*(j-i)*v+k);
其中tt可以用kruskal算法求出最小生成树求得。
代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#define INF 1e9
using namespace std;
struct road{int x,y,z,id;}sd[5005];
int n,m,t,v,k,fa[305],r[305][305],f[55];
bool bx[5005][55];
int cmp(road a,road b){return a.z<b.z;}
int find(int x)
{
if (fa[x]!=x) fa[x]=find(fa[x]);
return fa[x];
}
int work(int l,int r)
{
int i,j,cnt=0,len=0;
for (i=1;i<=n;i++) fa[i]=i;
for (i=1;i<=m;i++)
{
bool fff=false;
for (j=l;j<=r;j++) if (bx[sd[i].id][j]) {fff=true; break;}
if (fff) continue;
int a=find(sd[i].x),b=find(sd[i].y);
if (a!=b){fa[a]=b;cnt++;len+=sd[i].z;if (cnt==n-1) return len;}
}
return INF;
}
int main()
{
int i,j,p;
scanf("%d%d%d%d%d",&n,&m,&t,&v,&k);
for (i=1;i<=m;i++)
{
scanf("%d%d%d",&sd[i].x,&sd[i].y,&sd[i].z);
r[sd[i].x][sd[i].y]=r[sd[i].y][sd[i].x]=i;
sd[i].id=i;
}
sort(sd+1,sd+m+1,cmp);
scanf("%d",&p);
for (i=1;i<=p;i++)
{
int x,y,t1,t2;
scanf("%d%d%d%d",&x,&y,&t1,&t2);
int hh=r[x][y];
for (j=t1;j<=t2;j++) bx[hh][j]=true;
}
memset(f,0x7f,sizeof(f));f[0]=0;
for (i=1;i<=t;i++)
for (j=0;j<i;j++)
f[i]=min(f[i],f[j]+work(j+1,i)*(i-j)*v+k);
printf("%d",f[t]);
}