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\n");
        else printf("%d\n",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)

时间: 2024-11-05 18:48:13

UVAlive 7414 Squeeze the Cylinders a,b,c三种步数 搜索+最短路的相关文章

UVALive 6257 Chemist&#39;s vows --一道题的三种解法(模拟,DFS,DP)

题意:给一个元素周期表的元素符号(114种),再给一个串,问这个串能否有这些元素符号组成(全为小写). 解法1:动态规划 定义:dp[i]表示到 i 这个字符为止,能否有元素周期表里的符号构成. 则有转移方程:dp[i] = (dp[i-1]&&f(i-1,1)) || (dp[i-2]&&f(i-2,2))     f(i,k):表示从i开始填入k个字符,这k个字符在不在元素周期表中.  dp[0] = 1 代码: //109ms 0KB #include <ios

UVALive 7712 Confusing Manuscript 字典树 查询与s的编辑距离为1的字符串数量

/** 题目:UVALive 7712 Confusing Manuscript 链接:https://vjudge.net/problem/UVALive-7712 题意:给定n个不同的字符串,f(i)表示第i个字符串和其他字符串的编辑距离为1的个数. 编辑距离为1表示两个字符串其中一个可以通过删除任意位置某一个字符或者增加任意位置某一个字符或者替换任意位置某一个字符之后,两者匹配. 输出f(i)最大的字符串,如果f(i)==f(j) (i<j) 输出第i个字符串. 思路:字典树 主要是处理细

Linux识别ntfs及挂载的三种方式

NTFS-3G是一个开源软件,支持在Linux操作系统下读写NTFS格式的分区.它能快速且安全的操作Windows XP,Windows Server 2003, Windows 2000 以及WindowsVista文件系统. 1 .环境准备 安装该软件需要依赖于fuse, Centos6.*中应该默认安装过fuse: [[email protected] yum.repos.d]# rpm -q fuse fuse-2.8.3-4.el6.i686 已经安装 如果没有安装可以yum安装或者编

网络openvpn各种问题

今天先配置在同一个vmc下的一个openvpn里的两个虚拟机,同一个网段 一开始出现了如下问题: eth0: ERROR while getting interface flags: No such deviceDHCPDISCOVER on eth1 to 255.255.255.255 port 67 interval 3Network is unreachableSIOCADDRT: No such processDestination Host Unreachable 看 /etc/ne

Mysql+DRBD+Heartbeat 实现mysql高可用的双击热备(DRBD篇)

DRBD官方tar包下载地址:   http://oss.linbit.com/drbd/ 环境介绍: 系统版本:CentOS 6.4 (64位) 内核版本  2.6.32-358.el6.x86_64 软件版本:drbd-8.4.3.tar.gz 主:10.0.0.1   从:10.0.0.2 两台机器上的hosts都需要修改: [[email protected] ~]# vim /etc/hosts 10.0.0.1    node1 10.0.0.2    node2 两台服务器双网卡,

自己总结的 iOS ,Mac 开源项目以及库,知识点------持续更新

自己在 git  上看到一个非常好的总结的东西,但是呢, fork  了几次,就是 fork  不到我的 git 上,干脆复制进去,但是,也是认真去每一个每一个去认真看了,并且也是补充了一些,感觉非常棒,所以好东西要分享,为啥用 CN 博客,有个好处,可以随时修改,可以持续更新,不用每次都要再发表,感觉这样棒棒的 我们 自己总结的iOS.mac开源项目及库,持续更新.... github排名 https://github.com/trending,github搜索:https://github.

mysql备份恢复详解

前言 为什么需要备份数据? 数据的备份类型 MySQL备份数据的方式 备份需要考虑的问题 设计合适的备份策略 实战演练 使用cp进行备份 使用mysqldump+复制BINARY LOG备份 使用lvm2快照备份数据 使用Xtrabackup备份 总结 前言 我们试着想一想, 在生产环境中什么最重要?如果我们服务器的硬件坏了可以维修或者换新, 软件问题可以修复或重新安装, 但是如果数据没了呢?这可能是最恐怖的事情了吧, 我感觉在生产环境中应该没有什么比数据跟更为重要. 那么我们该如何保证数据不丢

反射,动态代理随笔

反射的基本概述 一个class文件被加载到内存的时候,JVM就会经行解剖,把这个class文件的所有成员全部解剖出来,然后JVM会创建一个Class对象,把这些成员信息全部都封装起来,所谓反射就是指:我们获取到这个Class对象,就相当于获取到了该类的所有成员信息,我们就能操又该类的所有成员. Java反射机制是在运行状态中,对于任意一个类,都能够知道这类的所有属性和方法; 对于任意一个对象,都能够调用它的任意一个方法和属性; 这种动态获取的细心以及动态调用它的任意一个方法和属性; 这种动态获取

Linux学习笔记——磁盘管理

废话不多说,直奔主题,磁盘常见的操作有创建.删除.查看磁盘分区,对磁盘进行软raid,创建磁盘阵列以及可以对磁盘重新组织,组建逻辑卷组以利于空间扩展.最后将创建的分区或者逻辑卷格式化后挂载使用.下边对相应的命令一一道来. fdisk [-l]  [device...] -l:查看硬盘挂载情况 [device]:所要操作的设备,例如/dev/sda 不使用-l 而直接后跟device则进入硬盘分区操作. 常用命令: -m:使用帮助: -p:显示指定磁盘的分区详细信息: -a:创建新分区: -d:删