题目大意:有一些码头由若干条边组成,有些时候有一些码头需要维修,这个期间不能使用这个码头。跟换航线的话会有一定的花费,求规定天数内的最小花费。
思路:最短路方面用SPFA就行,关键是动态规划。这个动规我想了很久,结果到最后发现自己想复杂了。我一开始想的是用SPFA处理出每一个不同的段,然后动规。这样做不仅分段不好分,动规也不好写。之后才发现,一共天数才100,枚举起点和终点才10000,套一个SPFA的O(kn)也不到1qw。。。
CODE:
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 110
using namespace std;
int days,points,change,edges,asks;
int cost[MAX][MAX],used[MAX][MAX];
bool v[MAX];
int head[MAX],total;
int next[MAX << 3],aim[MAX << 3],length[MAX << 3];
int f[MAX];
bool vis[MAX];
int dp[MAX];
inline void Add(int x,int y,int len);
inline void SPFA();
int main()
{
cin >> days >> points >> change >> edges;
for(int x,y,z,i = 1;i <= edges; ++i) {
scanf("%d%d%d",&x,&y,&z);
Add(x,y,z),Add(y,x,z);
}
cin >> asks;
for(int x,y,z,i = 1;i <= asks; ++i) {
scanf("%d%d%d",&z,&x,&y);
for(int j = x;j <= y; ++j)
used[j][z] = true;
}
for(int i = 1;i <= days; ++i)
for(int j = i;j <= days; ++j) {
memset(v,false,sizeof(v));
for(int k = i;k <= j; ++k)
for(int z = 2;z < points; ++z)
if(used[k][z]) v[z] = true;
SPFA();
cost[i][j] = f[points] * (f[points] >= 0x3f3f3f3f ? 1:(j - i + 1));
}
memset(dp,0x3f,sizeof(dp));
dp[0] = 0;
for(int i = 1;i <= days; ++i)
for(int j = 0;j < i; ++j)
dp[i] = min(dp[i],dp[j] + cost[j + 1][i] + change);
cout << dp[days] - change << endl;
return 0;
}
inline void Add(int x,int y,int len)
{
next[++total] = head[x];
aim[total] = y;
length[total] = len;
head[x] = total;
}
inline void SPFA()
{
static queue<int> q;
while(!q.empty()) q.pop();
memset(f,0x3f,sizeof(f));
memset(vis,false,sizeof(vis));
q.push(1);
f[1] = 0;
while(!q.empty()) {
int x = q.front(); q.pop();
vis[x] = false;
for(int i = head[x];i;i = next[i]) {
if(v[aim[i]]) continue;
if(f[aim[i]] > f[x] + length[i]) {
f[aim[i]] = f[x] + length[i];
if(!vis[aim[i]])
vis[aim[i]] = true,q.push(aim[i]);
}
}
}
}