hdu4848 dfs+剪枝

版权声明:转载请注明出处 https://blog.csdn.net/jay__bryant/article/details/81807428

题意:给定n个星球(编号1~n, n<=30),和从每个星球到达每个星球的时间,再给定到达每个星球的截止时间。从星球1出发,遍历2~n个星球,求每个星球的到达时间的总和。PS:每个星球可能不止经过一次!!!

dis[i][j]:i到j的最短距离,由floyd预处理
time[i]:到达i星球的时间,初始化-1。ans = sigma(time[i]) (2<=i<=n)
剪枝1:以达到当前点u的时间作为剩余点的到达时间(肯定小于搜下去的答案),
若还是大于了当前最优解,则没必要搜下去。
剪枝2:从当前点出发,只要有一个还未到达的点的到达时间大于dl则return;

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 35;
int time[N], ans;//time[i]:到达i的时间
int dl[N], dis[N][N];
int n;

void dfs(int u, int m, int ret)//当前点u,已经到达了m个点,当前总时间ret
{
    if(m==n)//如果到达了所有点,则更新答案
    {
        ans = min(ans, ret);
        return;
    }
    if(ret+time[u]*(n-m)>ans)//剪枝:以达到当前点u的时间作为剩余点的到达时间(肯定小于搜下去的答案) 
        return;              //若还是大于了当前最优解,则没必要搜下去
    for(int i = 2; i <= n; ++i)//剪枝:从当前点出发,只要有一个还未到达的点的到达时间大于dl则return;
        if(time[i]==-1 && time[u]+dis[u][i]>dl[i])
            return;
    for(int i = 2; i <= n; ++i)
        if(time[i]==-1)
        {
            time[i] = time[u]+dis[u][i];
            dfs(i, m+1, ret+time[i]);
            time[i] = -1;
        }
}

int main()
{
    while(~scanf("%d", &n))
    {
        for(int i = 1; i <= n; ++i)
            for(int j = 1; j <= n; ++j)
                scanf("%d", &dis[i][j]);
        for(int k = 1; k <= n; ++k)
            for(int i = 1; i <= n; ++i)
                for(int j = 1; j <= n; ++j)
                    dis[i][j] = min(dis[i][j], dis[i][k]+dis[k][j]);
        for(int i = 2; i <= n; ++i) scanf("%d", &dl[i]);
        memset(time, -1, sizeof(time));
        time[1] = 0;
        ans = INF;
        dfs(1, 1, 0);
        if(ans==INF) printf("-1\n");
        else printf("%lld\n", ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/jay__bryant/article/details/81807428