P1772 [ZJOI2006]物流运输

dp套spfa是最骚的qwq

首先要说明一点:这道题数据比较小,允许你用你觉得似乎过不了的复杂度过!

总体思路是这样的:

我们定义一个sp[i][j]数组表示第\(i\)天到第\(j\)天(闭区间)内的最短路,再定义dp[i]为前\(i\)天的最小代价。

那么就可以列出这么个柿子:

\[dp[i]=max_{j=1}^{i-1}dp[j]+sp[j+1][i]+k \]

在递推之前可以初始化\(dp[i]=sp[1][i]\)

\(20^2=400\)\(O(nm)\)spfa,随便写都保证不会T啦。。。

然后你就可以美滋滋地A了。

但我这个菜鸡还想了好久还不会

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define ll long long
const int maxn = 25, maxt = 105;
const int INF = 0x3f3f3f3f;
struct Edges
{
    int next, to, weight;
} e[1005];
int head[maxn], tot;
int dist[maxn];
bool block[maxn][maxt];
bool vis[maxn];
ll sp[maxt][maxt];
bool exist[maxn];
ll dp[maxt];
int n, m, t, cost;

void link(int u, int v, int w)
{
    e[++tot] = (Edges){head[u], v, w};
    head[u] = tot;
}
int spfa(int x, int y)
{
    //memset(vis, false, sizeof vis);
    memset(dist, 0x3f, sizeof dist);
    memset(exist, true, sizeof exist);
    for(int i = 1; i <= n; i++)
    {
        for(int j = x; j <= y; j++)
        {
            if(block[i][j])
            {
                exist[i] = false;
                break;
            }
        }
    }
    std::queue<int> q;
    dist[1] = 0; q.push(1); vis[1] = true;
    while(!q.empty())
    {
        int u = q.front(); q.pop(); vis[u] = false;
        for(int i = head[u]; i; i = e[i].next)
        {
            int v = e[i].to;
            if(!exist[v]) continue;
            if(dist[u] + e[i].weight < dist[v])
            {
                dist[v] = dist[u] + e[i].weight;
                if(!vis[v])
                {
                    q.push(v); vis[v] = true;
                }
            }
        }
    }
    return dist[n];
}
int main()
{
    scanf("%d%d%d%d", &t, &n, &cost, &m);
    while(m--)
    {
        int u, v, w; scanf("%d%d%d", &u, &v, &w);
        link(u, v, w); link(v, u, w);
    }
    scanf("%d", &m);
    while(m--)
    {
        int p, x, y; scanf("%d%d%d", &p, &x, &y);
        for(int i = x; i <= y; i++) block[p][i] = true;
    }
    for(int i = 1; i <= t; i++)
    {
        for(int j = i; j <= t; j++)
        {
            sp[i][j] = spfa(i, j);
            //printf("sb: %d\n", sp[i][j]);
        }
    }
    for(int i = 1; i <= t; i++)
    {
        dp[i] = sp[1][i] * i;
        for(int j = 1; j < i; j++)
        {
            if(sp[j + 1][i] != INF) dp[i] = std::min(dp[i], dp[j] + (i - j) * sp[j + 1][i] + cost);
            //printf("sb: %lld\n", dp[i]);
        }
    }
    printf("%lld\n", dp[t]);
    return 0;
}
posted @ 2018-10-31 21:49  Garen-Wang  阅读(99)  评论(0编辑  收藏  举报