2017 icpc Southeast USA J 题 Gym - 101617J Treasure Map 广搜好题




题意:

给出n个点,m条边,每一条边需要花 k 天才能走完,第一天的时候这个人在点 1

每一个点在第一天的时候有权值 g ,然后按照每天减少 d 天的速度减少,最多减少到零

题解:

广搜:从第一个点开始,对它周围的所有点进行遍历,依次类推


但普通广搜会爆掉,这里剪枝需要对题意有深刻的理解:我们发现,一个图里面某一天到某一个点方式有很多种方式,如果同一天在同一个点的这样的情况都搜索下去明显多了很多没有必要的东西,因此记忆一下,同一天到同一个点的选了权值大的权值小的就不要继续搜索了(所以在优先队列里面我们对时间进行排序)


下面的代码其实还可以继续剪枝,随时间的流逝,所有点都变成0的时候我们就不用继续搜索了


#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn = 1000+5;

int tot,n,m,ans;
int head[maxn];
int g[maxn],d[maxn];
int dis[maxn][maxn];

struct Node{
    int v,w,next;
}e[2*maxn];

struct node{
    int id,val,day;
    bool operator< (const node& rhs) const{
        return day>rhs.day;
    }
};

void addEdge(int u,int v,int w){
    e[tot].v = v;
    e[tot].w = w;
    e[tot].next = head[u];
    head[u] = tot++;
}

void bfs()
{
    memset(dis,0,sizeof(dis));
    priority_queue<node> q;
    node p;
    p.id = 1;
    p.val = g[1];
    p.day = 1;
    q.push(p);
    ans = g[1];

    dis[1][1] = g[1];
    while(!q.empty())
    {
        p = q.top(); q.pop();
        int u = p.id;

        for(int i=head[u];i!=-1;i=e[i].next)
        {
            int v = e[i].v;
            int w = e[i].w;
            node tmp = p;
            tmp.id = v;
            tmp.val += max(0,g[v]-d[v]*(p.day+w-1));
            tmp.day = p.day + w;
            if(tmp.val<=dis[v][tmp.day])  continue;
            dis[v][tmp.day] = tmp.val;
            q.push(tmp);
            ans = max(ans,tmp.val);
        }
    }
}

int main()
{
   //freopen("in.txt","r",stdin);
    while(~scanf("%d%d",&n,&m))
    {
        tot = 0;
        memset(head,-1,sizeof(head));
        for(int i=1;i<=n;i++)
            scanf("%d%d",&g[i],&d[i]);
        
        while(m--)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            addEdge(u,v,w);
            addEdge(v,u,w);
        }
        bfs();
        printf("%d\n",ans);
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章