HDU4848 Wow! Such Conquering! —— dfs + 剪枝

来源:互联网 发布:数组是原生类吗 编辑:程序博客网 时间:2024/05/20 07:16

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4848


题解: 一开始读错题目。以为每个点只能访问一遍。其实只要每个点都有被访问就可以了。

首先是用弗洛伊德算法求出每两点之间的最短路。然后再用dfs搜索。注意剪枝,否则会超时。


代码如下;

#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>#include <string>#include <vector>#include <map>#include <set>#include <queue>#include <sstream>#include <algorithm>using namespace std;#define pb push_back#define mp make_pair#define ms(a, b)  memset((a), (b), sizeof(a))#define eps 0.0000001typedef long long LL;const int INF = 2e9;const LL LNF = 9e18;const int maxn = 2000000+10;const int mod = 1e9+7;int dis[35][35],deadline[35];int vis[35];int n,ans;void dfs(int u, int cnt, int time, int sum){    if(cnt==n)    {        ans = min(ans,sum);        return;    }    //剪枝:    if(sum+time*(n-cnt)>=ans) return;    for(int i = 2; i<=n; i++)        if(!vis[i] && time+dis[u][i]>deadline[i]) return;    for(int i = 2; i<=n; i++)    {        if(!vis[i])        {            vis[i] = 1;            dfs(i,cnt+1,time+dis[u][i], sum+time+dis[u][i]);            vis[i] = 0;        }    }}void solve(){    for(int i = 1; i<=n; i++)        for(int j = 1; j<=n; j++)            scanf("%d",&dis[i][j]);    for(int i = 2; i<=n; i++)        scanf("%d",&deadline[i]);    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]);    ans = INF;    ms(vis,0);    dfs(1,1,0,0);    if(ans!=INF)        printf("%d\n",ans);    else        puts("-1");}int main(){    while(scanf("%d",&n)!=EOF){        solve();    }    return 0;}


0 0