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\n");
        else printf("%d\n",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\n");
        else printf("%d\n",ans);
    }
    return 0;
}
时间: 2024-10-05 06:05:33

hdu 4848 搜索+剪枝 2014西安邀请赛的相关文章

hdu 5887 搜索+剪枝

Herbs Gathering Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 687    Accepted Submission(s): 145 Problem Description Collecting one's own plants for use as herbal medicines is perhaps one of t

poj 1198 hdu 1401 搜索+剪枝 Solitaire

写到一半才发现可以用双向搜索4层来写,但已经不愿意改了,干脆暴搜+剪枝水过去算了. 想到一个很水的剪枝,h函数为  当前点到终点4个点的最短距离加起来除以2,因为最多一步走2格,然后在HDU上T了,又发现再搜索过程中,这个估价函数应该是递减的(贪心),再加上这个剪枝就过了. #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<list> #

hdu 3448(搜索+剪枝)Bag Problem

题意: 给n(n<=40)个物品和背包的容量w以及背包能装的物品个数k,每个物品有一个重量,问在满足背包的限制的情况下最多可以装多少物品. 思路 做过类似的题目,第一反应就是爆搜每个物品的两个状态放和不放.2^40肯定不行,来剪枝吧. 先把物品从小到大排序.一个有效的剪枝就是,最大的k个物品的重量和小于w那么这个重量和就是答案了,也是搜索中比较极限的情况,避免了去做搜索. 这样可以水过了,几乎没跑时间.5S有点吓人的意思?. 或许可以出可以卡这种剪枝的数据? 复杂度: 反正几乎没跑时间2333.

hdu 5305 (搜索+剪枝)

题意:有n个人(n<=8),每个人有一定数量的朋友,而和朋友的关系是线上朋友或者线下朋友(只能是其中一种).问每个人的线上朋友数量都等于线下朋友数量的方法数有多少. 做法:建成一个图,如果边的数目是奇数或者有人的度数是奇数,那个方法数肯定是0.否则,我们可以将边进行染色.假设黑色代表两个人之间是线上朋友,白色代表两个人之间是线下朋友.那么要满足条件,必须全部边有一半被染色,并且对于每个人相连的边有一半被染色.我们可以取一半的边进行染色,然后判断是不是每个人的一半相邻边被染色.这样,耗时为C(14

hdu 4848 Wow! Such Conquering! (暴搜+强剪枝)

Wow! Such Conquering! Time Limit: 15000/8000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 0    Accepted Submission(s): 0 Problem Description There are n Doge Planets in the Doge Space. The conqueror of Doge Space

hdu 4849 最短路 西安邀请赛 Wow! Such City!

http://acm.hdu.edu.cn/showproblem.php?pid=4849 会有很多奇怪的Wa的题,当初在西安就不知道为什么wa,昨晚做了,因为一些Sb错误也wa了很久,这会儿怎么写都会AC.... 收获: 1.还是基本都构思好在去敲代码,因为当时没过,昨晚心里有阴影,敲得很慢,而且最开始各种取模以防止漏掉,太保守了......以后一定先估算是不是需要取模防止TLE,当然时间够的话还是适当多取个模防止莫名其妙的错误.. 2.如果出错,注意参数是不是对的,最开始写好之后,因为m和

2014 北京、西安邀请赛

今年有幸能打两场邀请赛,真的是很幸运...但是打出来的效果就...本来都没脸写总结了的,后来想了想还是写了吧,不然这两场又白打了. 由于两场比赛相隔只有一周,所以我们就给自己放了10+天的假,玩是玩爽了,可惜比的就很烂了...稍微记录一下流水账吧,以后反思用. 先说一下北京的吧. 第一天热身赛,能做的只有两道,C题是输出随机数,A是24点,于是决定先猜几发C,猜了几个数都不对,然后就让队友去敲A了,敲完A之后队友发现C题ONE字很大!于是猜了个1,然后竟然就过了...B题是7次之内猜出一个每位都

【搜索剪枝】HDU 5469 Antonidas

通道 题意:给出1字母树,询问一字符串是否出现在该树中 思路:直接搜索剪枝,有人点分治?写了几发都T了..有人会了教我? 代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; struct Edge { int v, nxt; Edge () { } Edge (int _v, int _n) { v = _v, nxt = _n; } }; const in

hdu 4848 Wow! Such Conquering!

Wow! Such Conquering! Problem Description There are n Doge Planets in the Doge Space. The conqueror of Doge Space is Super Doge, who is going to inspect his Doge Army on all Doge Planets. The inspection starts from Doge Planet 1 where DOS (Doge Olymp