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;
}

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