【20160811】noip模拟-未完
T1
T2
T3 小奇回地球
【问题描述】
简单来说,它要从标号为1的星球到标号为n的星球,某一些星球之间有航线。由于超时空隧道的存在,从一个星球到另一个星球时间可能会倒流,而且,从星球a到b耗费的时间和星球b到a耗费的时间不一定相同。
宇宙法规定:“禁止在出发时间前到达目的地。”
每艘飞船上都有速度调节装置,可以调节飞行的时间。其功能可以使得整次航程中所有两星球间的飞行时间增加或减少相同的整数值。你的任务是帮助它调整速度调节器,找出一条最短时间到达目的地的路径。
【输入格式】
输入文件包含多组数据,第1个数为T,表示数据组数。
对于每组数据,输入第1行为两个正整数n,m,为星球的个数和星球间的路线数。接下来m行,每行三个整数i,j和t,表示由星球i到星球j飞行的时间为t。由i到j最多只会有一条飞行线路。
【输出格式】
输出文件共T行,每组数据输出一行。
如果可以通过调节速度调节器完成任务,则输出一个非负整数,表示由星球1到星球n的最短时间。(注意最短时间要大于或者等于0)。
如果不能由星球1到达星球n,则输出-1。
【样例输入】
1
4 5
1 2 1
1 3 1
2 3 -3
3 1 1
3 4 1
【样例输出】
2
【样例解释】
把速度控制器的值设为1,相当于每个时间值加1,得到的最短路径为1→2→3→4,所需时间为2+(-2)+2=2。
【数据范围】
1,2号测试点,保证所有星球出度不超过1
3,4号测试点,n<=10
5,6号测试点,-100<=t<=100
对于100%的数据T<=10,n<=100,m<=n*(n-1),-100000<=t<=100000
数据随机和构造结合生成
这题的题意好含糊。。理解错了好多次。。理解错了就不会做了(迷之微笑)
题意:给定一个有向图,每条边有一个权值,可以给所有边加或减同一个值k(k为整数),使得1到n的最短路存在,最短路>=0且尽量小。
正确理解:
如果1到n的路径中有负环,那最短路就不存在;
如果1到n的最短路是负数,那也不满足题意。
题解:
我们可以发现k具有单调性:如果+k都还存在负环or最短路为负,那比k小的更加不满足题意;反之,比k大的必定满足题意。
二分k,spfa判断图中是否有负环、并求出最短路,判断是否满足题意。
注意:判断负环前应删去那些与起点、终点不是都联通的点!
比如这种情况,图中存在负环,但是与1到n的最短路无关,错误输出为105,正确输出为5。
优化:用spfa判断负环的方法
判断给定的有向图中是否存在负环。
利用 spfa 算法判断负环有两种方法:
1) spfa 的 dfs 形式,判断条件是存在一点在一条路径上出现多次。
2) spfa 的 bfs 形式,判断条件是存在一点入队次数大于总顶点数。
SPFA的两种写法,bfs和dfs,bfs判别负环不稳定,相当于限深度搜索,但是设置得好的话还是没问题的,dfs的话判断负环很快。
我原本的方法是在bfs里加一个数组,记录每个点入队了多少次,如果有一个点入队次数大于n则有负环。
时间是这样的:
改成dfs:
改成dfs这里调了挺久的。但是的确快了很多。
- #include<cstdio>
- #include<cstdlib>
- #include<cstring>
- #include<iostream>
- #include<queue>
- using namespace std;
- const int N=,Inf=(int)1e9;
- struct node{
- int x,y,d,next;
- }a[N*N];
- int n,m,len,dis[N],first[N];
- bool in[N],can[N],vis[N];
- queue<int> q;
- int read()
- {
- int x=,f=;char ch=getchar();
- while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
- while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
- return x*f;
- }
- void ins(int x,int y,int d)
- {
- len++;
- a[len].x=x;a[len].y=y;a[len].d=d;
- a[len].next=first[x];first[x]=len;
- }
- int minn(int x,int y){return x<y ? x:y;}
- void dfs(int x)
- {
- vis[x]=;
- for(int i=first[x];i;i=a[i].next)
- if(!vis[a[i].y]) dfs(a[i].y);
- }
- bool dfs_spfa(int x,int ad)
- {
- in[x]=;
- for(int i=first[x];i;i=a[i].next)
- {
- int y=a[i].y;
- if(dis[y]>dis[x]+a[i].d+ad && can[y])
- {
- if(in[y]) return ;//负边成环
- dis[y]=dis[x]+a[i].d+ad;//虽然dis[x]=dis[y]=0,但如果是负边,a[i].d+ad<0
- if(dfs_spfa(y,ad)) return ;
- }
- }
- in[x]=;
- return ;
- }
- void bfs_spfa(int ad)
- {
- while(!q.empty()) q.pop();
- memset(dis,,sizeof(dis));
- memset(in,,sizeof(in));
- q.push();dis[]=;in[]=;
- while(!q.empty())
- {
- int x=q.front();in[x]=;q.pop();
- for(int i=first[x];i;i=a[i].next)
- {
- int y=a[i].y;
- int d=a[i].d+ad;
- if(dis[y]>dis[x]+d && can[y])
- {
- dis[y]=dis[x]+d;
- if(!in[y]) in[y]=,q.push(y);
- }
- }
- }
- }
- bool judge(int ad)
- {
- // 判断是否有负环
- for(int i=;i<=n;i++)
- if(can[i])
- {
- memset(dis,,sizeof(dis));//不用算具体数值,只要求到有负环即可。
- memset(in,,sizeof(in));
- if(dfs_spfa(i,ad)) return ;//dfs_spfa(i)相当于找i这个点是不是在一个负环中,所以要每个点都做一遍,不是在负环中很快就会跳出,否则就遍历一遍负环。
- }
- //屏蔽了的这种方法理论上也可以,但是相当于用dfs做了一遍spfa,比bfs更慢,超时。
- /* memset(dis,63,sizeof(dis));dis[1]=0;
- memset(in,0,sizeof(in));
- if(can[1]==0) return 0;
- if(can[1]==1 && dfs_spfa(1,ad)) return 0;*/
- //跑最短路
- bfs_spfa(ad);
- if(dis[n]>= && dis[n]<=Inf) return ;
- return ;
- }
- int main()
- {
- // freopen("a.in","r",stdin);
- freopen("earth.in","r",stdin);
- freopen("earth.out","w",stdout);
- int T;
- scanf("%d",&T);
- while(T--)
- {
- len=;
- memset(first,,sizeof(first));
- n=read(),m=read();
- int mn=;
- for(int i=;i<=m;i++)
- {
- int x=read(),y=read(),d=read();
- ins(x,y,d);
- }
- memset(vis,,sizeof(vis));
- dfs();
- for(int i=;i<=n;i++)
- {
- if(vis[i]) can[i]=;
- else can[i]=;
- //can[x]=1 x点与起点联通
- }
- for(int i=;i<=n;i++)
- {
- if(can[i])
- {
- memset(vis,,sizeof(vis));
- dfs(i);
- if(!vis[n]) can[i]=;
- }
- }//can[x]=1 x点与起点、终点都联通
- int l=-,r=,ans=-;
- while(l<=r)//二分加或减多少
- {
- int mid=(l+r)>>;
- if(judge(mid)) ans=dis[n],r=mid-;
- else l=mid+;
- // printf("l = %d r = %d\n",l,r);
- }
- printf("%d\n",ans);
- }
- return ;
- }
【20160811】noip模拟-未完的更多相关文章
- NOIP模拟题汇总(加厚版)
\(NOIP\)模拟题汇总(加厚版) T1 string 描述 有一个仅由 '0' 和 '1' 组成的字符串 \(A\),可以对其执行下列两个操作: 删除 \(A\)中的第一个字符: 若 \(A\)中 ...
- NOIP模拟赛20161022
NOIP模拟赛2016-10-22 题目名 东风谷早苗 西行寺幽幽子 琪露诺 上白泽慧音 源文件 robot.cpp/c/pas spring.cpp/c/pas iceroad.cpp/c/pas ...
- 大家AK杯 灰天飞雁NOIP模拟赛题解/数据/标程
数据 http://files.cnblogs.com/htfy/data.zip 简要题解 桌球碰撞 纯模拟,注意一开始就在袋口和v=0的情况.v和坐标可以是小数.为保险起见最好用extended/ ...
- Codeforces Round #395 (Div. 2)(未完)
2.2.2017 9:35~11:35 A - Taymyr is calling you 直接模拟 #include <iostream> #include <cstdio> ...
- 布隆过滤器(Bloom Filter) 未完待续
布隆过滤器雏形 未完待续..... 计算错误率 现在有一个空额布隆过滤器, 过滤器里的bit array的大小是m. 咱来插入一个元素. 这次插入过程中的第一个hash函数会算出一个位置, 然后把这个 ...
- 从Socket入门到BIO,PIO,NIO,multiplexing,AIO(未完待续)
Socket入门 最简单的Server端读取Client端内容的demo public class Server { public static void main(String [] args) t ...
- 【noip模拟赛4】Matrix67的派对 暴力dfs
[noip模拟赛4]Matrix67的派对 描述 Matrix67发现身高接近的人似乎更合得来.Matrix67举办的派对共有N(1<=N<=10)个人参加,Matrix67需要把他们 ...
- Go web编程学习笔记——未完待续
1. 1).GOPATH设置 先设置自己的GOPATH,可以在本机中运行$PATH进行查看: userdeMacBook-Pro:~ user$ $GOPATH -bash: /Users/user/ ...
- NOIP模拟赛-2018.11.7
NOIP模拟赛 如果用命令行编译程序可以发现没加头文件之类的错误. 如果用命令行编译程序可以发现没加头文件之类的错误. 如果用命令行编译程序可以发现没加头文件之类的错误. 编译之前另存一份,听说如果敲 ...
随机推荐
- 怎么防止别人动态在你程序生成代码(怎么防止别人反编译你的app)
1.本地数据加密 iOS应用防反编译加密技术之一:对NSUserDefaults,sqlite存储文件数据加密,保护帐号和关键信息 2.URL编码加密 iOS应用防反编译加密技术之二:对程序中出现的U ...
- shiro笔记
控制某一角色拥有此选项 上图 标签为shiro:hasRole表示 此时只有admin角色才拥有 系统用户管理和角色管理两个tab 页 上图 标签为shiro:hasPermission表示 此时只有 ...
- 04-Mysql----初识sql语句
本节课先对mysql的基本语法初体验. 操作文件夹(库) 增 create database db1 charset utf8; 查 # 查看当前创建的数据库 show create database ...
- virsh查看迁移信息的两个命令
virsh qemu-monitor-command uuid --hmp info migrate, 能看到迁移所设置的相关参数,和进度相关信息: virsh domjobinfo uuid命令, ...
- Leetcode 3. Longest Substring Without Repeating Characters (Medium)
Description Given a string, find the length of the longest substring without repeating characters. E ...
- 一些排序算法的Python实现
''' Created on 2016/12/16 Created by freeol.cn 一些排序算法的Python实现 @author: 拽拽绅士 ''' '''值交换''' def swap( ...
- 并查集——poj1611(入门)
传送门:The Suspects 并查集水题 #include <iostream> #include <cstdio> #include <algorithm> ...
- java计算两个日期之间的相隔天数
[原创] 之前在很多竞赛的题目中有这样饿一类题,计算给定两个日期之间的相隔天数,或者很多类似的题目,都是需要转化到这个问题上时,之前用c++写的时候思想是这样的,一个结构体,包括年月日,还有一个计算下 ...
- JAVA第八周课堂笔记
- systemPath
<dependency> <groupId>com.aliyun.mns</groupId> <artifactId>aliyun-sdk-mn ...