zoukankan      html  css  js  c++  java
  • UVAlive 7414 Squeeze the Cylinders a,b,c三种步数 搜索+最短路

    You are playing a game with your elder brother.
    First, a number of circles and arrows connecting some pairs of the circles are drawn on the ground.
    Two of the circles are marked as the start circle and the goal circle.
    At the start of the game, you are on the start circle. In each turn of the game, your brother tells
    you a number, and you have to take that number of steps. At each step, you choose one of the arrows
    outgoing from the circle you are on, and move to the circle the arrow is heading to. You can visit the
    same circle or use the same arrow any number of times.
    Your aim is to stop on the goal circle after the fewest possible turns, while your brother’s aim is to
    prevent it as long as possible. Note that, in each single turn, you must take the exact number of steps
    your brother tells you. Even when you visit the goal circle during a turn, you have to leave it if more
    steps are to be taken.
    If you reach a circle with no outgoing arrows before completing all the steps, then you lose the
    game. You also have to note that, your brother may be able to repeat turns forever, not allowing you
    to stop after any of them.
    Your brother, mean but not too selfish, thought that being allowed to choose arbitrary numbers
    is not fair. So, he decided to declare three numbers at the start of the game and to use only those
    numbers.
    Your task now is, given the configuration of circles and arrows, and the three numbers declared, to
    compute the smallest possible number of turns within which you can always finish the game, no matter
    how your brother chooses the numbers.
    Input
    The input file contains several test cases, each of them as described below.
    The input consists must be formatted as follows:
    n m a b c
    u1 v1
    .
    .
    .
    um vm
    All numbers in a test case are integers. n is the number of circles (2 ≤ n ≤ 50). Circles are numbered
    1 through n. The start and goal circles are numbered 1 and n, respectively. m is the number of arrows
    (0 ≤ m ≤ n(n−1)). a, b, and c are the three numbers your brother declared (1 ≤ a, b, c ≤ 100). The
    pair, ui and vi
    , means that there is an arrow from the circle ui to the circle vi
    . It is ensured that
    ui ̸= vi for all i, and ui ̸= uj or vi ̸= vj if i ̸= j.
    Output
    For each test case, print the smallest possible number of turns within which you can always finish the
    game on a line by itself.
    Print ‘IMPOSSIBLE’ if your brother can prevent you from reaching the goal, by either making you
    repeat the turns forever or leading you to a circle without outgoing arrows.
    Explanations:
    On the first case of Sample Input below, your brother may choose 1 first, then 2, and repeat these
    forever. Then you can never finish.
    On the second case (figure on the right), if your
    brother chooses 2 or 3, you can finish with a single
    turn. If he chooses 1, you will have three options.
    • Move to the circle 5. This is a bad idea: Your
    brother may then choose 2 or 3 and make you
    lose.
    • Move to the circle 4. This is the best choice:
    From the circle 4, no matter any of 1, 2, or 3
    your brother chooses in the next turn, you can
    finish immediately.
    • Move to the circle 2. This is not optimal for you.
    If your brother chooses 1 in the next turn, you cannot finish yet. It will take three or more turns
    in total.
    In summary, no matter how your brother acts, you can finish within two turns. Thus the answer is
    2.
    Sample Input
    3 3 1 2 4
    1 2
    2 3
    3 1
    8 12 1 2 3
    1 2
    2 3
    1 4
    2 4
    3 4
    1 5
    5 8
    4 6
    6 7
    4 8
    6 8
    7 8
    Sample Output
    IMPOSSIBLE
    2

    题意:给你n个点(n<=50),然后有些点之间会有一条路,路是单向的,每个回合让你走a,b,c三种步数中的任意一种(a,b,c<=100),问你最少需要多少个回合才能保证一定能从1点到达n点;

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <iostream>
    #include <cmath>
    #include <queue>
    #include <vector>
    #define MM(a,b) memset(a,b,sizeof(a));
    #define inf 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    #define CT continue
    #define SC scanf
    const int N=1e5+10;
    int dis[55][7],step[7],vis[55][105];
    int n,m,a,b,c;
    vector<int> nxt[55][6],G[55];
    
    void initdfs(int root,int u,int stepf,int d)
    {
        vis[u][d]=1;
        if(d==0) {
            nxt[u][stepf].push_back(root);
            return;
        }
        for(int i=0;i<G[u].size();i++){
            int v=G[u][i];
            if(!vis[v][d-1]) initdfs(root,v,stepf,d-1);
        }
    }
    
    void initstep()
    {
        for(int i=1;i<=n;i++)
        for(int j=1;j<=3;j++) {
            MM(vis,0);
            initdfs(i,i,j,step[j]);
        }
    }
    
    void init()
    {
        for(int i=1;i<=n;i++) {
            nxt[i][1].clear();
            nxt[i][2].clear();
            nxt[i][3].clear();
            G[i].clear();
        }
    }
    
    struct node{
       int v,dis4;
       bool operator<(const node &a) const{
           return this->dis4>a.dis4;
       }
    };
    priority_queue<node> q;
    
    int dist_road(int s)
    {
        while(q.size()) q.pop();
        MM(dis,inf);
        MM(dis[s],0);
    
        q.push((node){s,0});
        while(q.size()){
            node cur=q.top();q.pop();
            int u=cur.v;
            if(dis[u][4]<cur.dis4) CT;
            for(int i=1;i<=3;i++)
            for(int j=0;j<nxt[u][i].size();j++){
                int v=nxt[u][i][j];
                if(dis[v][i]>dis[u][4]+1)
                   dis[v][i]=dis[u][4]+1;
                if(dis[v][4]>max(max(dis[v][1],dis[v][2]),dis[v][3])){
                   dis[v][4]=max(max(dis[v][1],dis[v][2]),dis[v][3]);
                   q.push((node){v,dis[v][4]});
                }
    
            }
        }
        return dis[1][4];
    }
    
    int main()
    {
        while(~SC("%d%d%d%d%d",&n,&m,&step[1],&step[2],&step[3]))
        {
            init();
            for(int i=1;i<=m;i++){
                int u,v;
                SC("%d%d",&u,&v);
                G[u].push_back(v);
            }
    
            initstep();
    
            int k=dist_road(n);
            if(k==inf) printf("IMPOSSIBLE
    ");
            else printf("%d
    ",k);
        }
        return 0;
    }
    

     分析:

    1.比赛时有个很关键的地方没有分析出来那就是对于点n,如果答案有解,那么n向前操作一个回合后,

    至少存在一个点,使得其走a,b,c三种步数都可以到达n,然后再拿这些点去更新其他的点,并且一定可以

    更新到1号点

    2.

    void initdfs(int root,int u,int stepf,int d)
    {
        vis[u][d]=1;
        if(d==0) {
            nxt[u][stepf].push_back(root);
            return;
        }
        for(int i=0;i<G[u].size();i++){
            int v=G[u][i];
            if(!vis[v][d-1]) initdfs(root,v,stepf,d-1);
        }
    }
    void initstep()
    {
        for(int i=1;i<=n;i++)
        for(int j=1;j<=3;j++) {
            MM(vis,0);
            initdfs(i,i,j,step[j]);
        }
    }

      对于这段初始化每个点走a,b,c三种步数能够到达的点,刚开始没加vis[][]数组:考虑一个完全图(任意两点之间都有边相连接)的话,那么对于50个点,可以走100步,每步都可以走50个点,复杂度就是

    50*100^50显然会超时,,因为进行了大量的重复计算,加个有效的优化,vis数组,vis[a][b],表示对于

    走到a节点剩余步数为b步,,,那么复杂度就降为50*(50*100)

  • 相关阅读:
    第一章
    第一章 计算机系统漫游
    hihocoder #1014 : Trie树
    第一章
    来个小目标
    poj 1056 IMMEDIATE DECODABILITY
    poj 2001 Shortest Prefixes
    __name__ 指示模块应如何被加载
    Python 常用函数time.strftime()简介
    CentOS安装beEF做XSS平台
  • 原文地址:https://www.cnblogs.com/smilesundream/p/5825941.html
Copyright © 2011-2022 走看看