• hdu 4848 搜索+剪枝 2014西安邀请赛


    http://acm.hdu.edu.cn/showproblem.php?pid=4848

    比赛的时候我甚至没看这道题,事实上不难....

    可是说实话,如今对题意还是理解不太好......

    犯的错误:
    1、floy循环次序写错,

    2、搜索的时候。应该先推断i是不是能够搜(就是可不可能产生解)。然后标记vis[i]=1。我二逼的先标记vis[i]=1,然后推断i是不是可搜,这样肯定会导致有些时候,cnt!=n

    我的剪枝方法(2546MS AC):

    搜下一个结点之前。确保时间小于全部的未訪问的结点的Deadline

    //#pragma comment(linker, "/STACK:102400000,102400000")
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <string>
    #include <iostream>
    #include <iomanip>
    #include <cmath>
    #include <map>
    #include <set>
    #include <queue>
    using namespace std;
    
    #define ls(rt) rt*2
    #define rs(rt) rt*2+1
    #define ll long long
    #define ull unsigned long long
    #define rep(i,s,e) for(int i=s;i<e;i++)
    #define repe(i,s,e) for(int i=s;i<=e;i++)
    #define CL(a,b) memset(a,b,sizeof(a))
    #define IN(s) freopen(s,"r",stdin)
    #define OUT(s) freopen(s,"w",stdout)
    const ll ll_INF = ((ull)(-1))>>1;
    const double EPS = 1e-8;
    const int INF = 1e9+7;
    const int MAXN = 50;
    
    int n;
    int mat[MAXN][MAXN];
    int dis[MAXN][MAXN];
    int dead[MAXN];
    void floy()
    {
        repe(k,1,n)
        for(int i=1;i<=n;i++)
            repe(j,1,n)
    
                    dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
    }
    int ans;
    int vis[MAXN];
    
    void dfs(int u, int t, int cnt,int tmp)
    {
        if(dead[u]<t || tmp>ans)return;
        if(cnt == n)
        {
            ans=min(ans,tmp);
            return;
        }
        for(int i=2;i<=n;i++)
            if(!vis[i] && dead[i]>=t+dis[u][i])
            {
                int flag=0;
                for(int j=2;j<=n;j++)
                    if(!vis[j] && t+dis[u][i]>dead[j] && i!=j)
                            flag=1;
                if(flag)continue;
                vis[i]=1;
                dfs(i,t+dis[u][i],cnt+1,tmp+dis[u][i]*(n-cnt));
                vis[i]=0;
            }
    }
    
    int main()
    {
        //IN("hdu4848.txt");
        while(~scanf("%d",&n))
        {
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    scanf("%d",&mat[i][j]),dis[i][j]=mat[i][j];
            floy();
            dead[1]=INF;
            repe(i,2,n)
                scanf("%d",&dead[i]);
            ans=INF;
            CL(vis,0);
            vis[1]=1;
            dfs(1,0,1,0);
            if(ans == INF)printf("-1
    ");
            else printf("%d
    ",ans);
        }
        return 0;
    }
    

    网上的方法:(359ms AC)

    事实上剪枝思路跟我一样,可是比我的更好

    倘若搜到当前结点,检查全部的未訪问的结点,假设不管以哪个未訪问结点为起点都不可能得到解,直接返回,相当于比我少遍历一层并且少了非常多反复

    //#pragma comment(linker, "/STACK:102400000,102400000")
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <string>
    #include <iostream>
    #include <iomanip>
    #include <cmath>
    #include <map>
    #include <set>
    #include <queue>
    using namespace std;
    
    
    #define ls(rt) rt*2
    #define rs(rt) rt*2+1
    #define ll long long
    #define ull unsigned long long
    #define rep(i,s,e) for(int i=s;i<e;i++)
    #define repe(i,s,e) for(int i=s;i<=e;i++)
    #define CL(a,b) memset(a,b,sizeof(a))
    #define IN(s) freopen(s,"r",stdin)
    #define OUT(s) freopen(s,"w",stdout)
    const ll ll_INF = ((ull)(-1))>>1;
    const double EPS = 1e-8;
    const int INF = 1e9+7;
    const int MAXN = 50;
    
    
    int n;
    int mat[MAXN][MAXN];
    int dis[MAXN][MAXN];
    int dead[MAXN];
    
    
    void floy()
    {
        repe(k,1,n)
        for(int i=1;i<=n;i++)
            repe(j,1,n)
    
    
                    dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
    }
    int ans;
    int vis[MAXN];
    
    
    void dfs(int u, int t, int cnt,int tmp)
    {
        if(dead[u]<t || tmp>ans)return;
        if(cnt == n)
        {
            ans=min(ans,tmp);
            return;
        }
        for(int i=2;i<=n;i++)
            if(!vis[i] && t+dis[u][i]>dead[i])
                return;
        for(int i=2;i<=n;i++)
            if(!vis[i] && dead[i]>=t+dis[u][i])
            {
                vis[i]=1;
                dfs(i,t+dis[u][i],cnt+1,tmp+dis[u][i]*(n-cnt));
                vis[i]=0;
            }
    }
    
    
    int main()
    {
        //IN("hdu4848.txt");
        while(~scanf("%d",&n))
        {
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    scanf("%d",&mat[i][j]),dis[i][j]=mat[i][j];
            floy();
            dead[1]=INF;
            repe(i,2,n)
                scanf("%d",&dead[i]);
            ans=INF;
            CL(vis,0);
            vis[1]=1;
            dfs(1,0,1,0);
            if(ans == INF)printf("-1
    ");
            else printf("%d
    ",ans);
        }
        return 0;
    }
    


  • 相关阅读:
    win7(64bit)python相关环境模块搭建
    memcached在windows下的安装与命令使用方法
    pomelo流程
    pomelo 初始化配置...
    pomelo组件..
    <转>如何高效快速看懂Android源码
    源码学习
    计划
    Android面试题集锦 (转)
    Android 面试题(转)
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/5239954.html
Copyright © 2020-2023  润新知