2017衢州联赛第四题题解
来源:互联网 发布:mac 终端怎么切换用户 编辑:程序博客网 时间:2024/05/01 21:37
环游衢州
(walk.pas/c/cpp)
【问题描述】
Jason 想要带着他新叫的朋友环游 QZ, 于是他把 QZ 划分成了 n 个地方,已知这 n 个地方由 m 条双向边相连接,并且他把 n 个地方分别赋予了一个 happy 值,他希望按照 happy 值严格递减的方法去游览QZ, 这样他可以把一些最美的地方介绍给他朋友。 然而 Jason 的心态不太好,所以他有 k 次从小向大走的机会,问他最多能够带他的朋友游览几个地方,如果能够游览的地方数超过 10^9+7则输出“ infinity”
【输入格式】
第一行两个数 n,m, k 表示地方数、边数和反向次数
第二行 n 个数表示 n 个地点的 happy 值
然后 m 行每行两个数 a,b 表示 a, b 之间有一条无向边
【输出格式】
一行一个数表示最多能够游览的地方数或者“ infinity”
【输入样例1】
1 3 1
2147483647
1 1
1 1
1 1
【输出样例1】
2
【输入样例2】
10 30 20
720472486 1616090782 1659830133 376600248 1485380712 819748825 1072214931 1957734249 95302927 622052677
2 6
1 6
10 2
8 4
8 2
9 6
1 4
9 7
1 4
4 7
7 1
4 5
10 6
7 7
8 5
7 8
6 2
7 2
3 9
6 8
3 4
9 8
8 8
4 5
8 7
5 6
2 2
9 7
3 1
9 1
【输出样例2】
105
【样例解释】
在 1 号点的自环上走一步即可到达两个点。
【 数据说明】
对于 10%的数据: 1<=n<=10, 1<=m<=30, k=0
对于 30%的数据: 1<=n<=500, 1<=m<=2500, k=0
对于 60%的数据: 1<=n<=1000, m<=3000, k<=20
对于 100%的数据: 1<=n<=10^5, 1<=m<=2*10^5,k<=80, happy 值小于等于 2^31-1
【提示】
一个地点经过两次按两个地点算。
pascal 请勿使用 readln。
【题目分析】
这道题是典型的将求最长单调序列套在图的模型上,那么先将这个模型。
首先为了方便推,a[i]需要排序,但是这样会有一个严重的问题就是原来的图会被打乱,所以在实际操作中不能这样做,正确的做法应该另设一个数组id[i],表示排名为i的点在图中的具体位置,初始时id[i]=i,排序的时候排的标准是a[i],但是调动的是id[i],这样就可以不会改变原来的图了。
接下来就是DP的推法(以最长降为例):
f[i]同在序列中的定义,就是以i为结尾的最长降的路。转移时为了能得到更优的答案所以是从大到小推(这就是为什么需要进行排序),比较简单,代码如下:
for (int i=n;i;i--) for (int j=lnk[id[i]];j;j=nxt[j]) if (a[id[i]]<a[son[j]]) f[id[i]]=max(f[id[i]],f[son[j]]+1);
回到这道题,不过就是添加了一个可以逆走的次数,那么就把逆走的次数带到转移中,f[T][i]表示使用了T次逆走,目前在i点的距离,转移方程就比较简单,详细看代码。
【复杂度】
时间:O(nT)(实际偏大); 空间:O(nT);
【代码】
#include<cstdio>#include<cstring>#include<cstdlib>#include<algorithm>using namespace std;#define maxn 100005#define maxe 400005#define tt 1000000007int n,e,k,tot,ans,a[maxn],id[maxn],son[maxe],nxt[maxe],lnk[maxn],f[85][maxn];inline void readi(int &x){ x=0; char ch=getchar(); while ('0'>ch||ch>'9') ch=getchar(); while ('0'<=ch&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}}void _add(int x,int y){ tot++; son[tot]=y; nxt[tot]=lnk[x]; lnk[x]=tot;}inline int cmp_id(int i,int j){return a[i]<a[j];}void _init(){ freopen("walk.in","r",stdin); freopen("walk.out","w",stdout); readi(n); readi(e); readi(k); for (int i=1;i<=n;i++) {readi(a[i]); id[i]=i;} tot=0; memset(son,0,sizeof(son)); memset(nxt,0,sizeof(nxt)); memset(lnk,0,sizeof(lnk)); for (int i=1;i<=e;i++) { int x,y; readi(x); readi(y); _add(x,y); _add(y,x); } sort(id+1,id+n+1,cmp_id);}void _solve(){ memset(f,0,sizeof(f)); for (int i=n;i;i--) for (int j=lnk[id[i]];j;j=nxt[j]) if (a[son[j]]>a[id[i]]) f[0][id[i]]=max(f[0][id[i]],f[0][son[j]]+1); for (int t=1;t<=k;t++) for (int i=n;i;i--) for (int j=lnk[id[i]];j;j=nxt[j]) if (a[id[i]]<a[son[j]]) f[t][id[i]]=max(f[t][id[i]],f[t][son[j]]+1); else f[t][id[i]]=max(f[t][id[i]],f[t-1][son[j]]+1); ans=0; for (int i=1;i<=n;i++) for (int j=0;j<=k;j++) ans=max(ans,f[j][i]); printf("%d\n",ans+1);}int main(){ _init(); _solve(); return 0;}
PS:
如果各位神犇发现本博客有误,请一定及时告诉作者我这个菜鸟噢,新手上路,请多指教。
- 2017衢州联赛第四题题解
- 2017衢州联赛第三题题解
- 2017年衢州联赛 T2
- (hdu6075) 2017杭电多校联赛第四场-Questionnaire 思维题
- (hdu6077)2017杭电多校联赛第四场-Time To Get Up 模拟题
- HDU6077 2017杭电多校联赛第四场-Time To Get Up
- HDU6070 2017杭电多校联赛第四场-Dirt Ratio
- 2012年分区联赛普级组第四题 …
- 2012年分区联赛普级组第四题 …
- NOIP第四题解题报告
- 多校联赛第四场
- NYIST--2017大一新生第四次周赛题解
- NOIP2015普及组第四题解题报告
- NOIP2016普及组 第四题 题解
- 2017年第23届全国青少年信息学奥林匹克竞赛分区联赛提高组复赛题解报告
- 2017年第23届全国青少年信息学奥林匹克竞赛分区联赛提高组初赛题解报告
- 【日常学习】【卡特兰数】【栈】2003年NOIP全国联赛普及组第三题 题解
- 2016多校联赛5题解
- 详解设计模式——建造者模式
- 滑动冲突(上)
- Android接收蓝牙万用表数据
- Makefile中=与:=的准确定义与区别(转载)
- eclipse搭建SSH框架
- 2017衢州联赛第四题题解
- HeadFirstJava 7,8,9
- 设计模式学习笔记(Java篇)之单例模式
- Android真机调试异常java.net.SocketTimeoutException
- 【LeetCode】129. Sum Root to Leaf Numbers
- 湘潭OJ 1264 挺好的一道贪心题
- BZOJ 1468: Tree
- 下载文件进度显示--小小Demo——桃先森
- 防新闻头条视频管道(布局)