QZEZOJ 环游QZ题解--zhengjun
题目描述
\(FLY\)想要带着他新叫的朋友环游\(QZ\),于是他把\(QZ\)划分成了\(n\)个地方,已知这\(n\)个地方由\(m\)条双向边相连接,并且他把\(n\)个地方分别赋予了一个\(happy\)值,他希望按照\(happy\)值严格递减\((a>b)\)的方法去游览\(QZ\),这样他可以把一些最美的地方介绍给他朋友。如果能够游览的地方数超过10^9+7则输出infinity
输入
第一行两个数\(n\),\(m\)表示地方数、边数
第二行n个数表示\(n\)个地点的\(happy\)值
然后m行每行两个数\(a\),\(b\)表示\(a\),\(b\)之间有一条无向边
输出
一行一个数表示最多能够游览的地方数或者infinity
样例输入
10 30
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
样例输出
5
提示
对于10%的数据:\(1<=n<=10,1<=m<=30\)
对于30%的数据:\(1<=n<=500,1<=m<=2500\)
对于60%的数据:\(1<=n<=1000,m<=3000\)
对于100%的数据:\(1<=n<=10^5,1<=m<=2*10^5\),\(happy\)值小于等于2^31-1
思路
首先表明,我的思路并不是正解,但是
条条大路通罗马
我的方法也许会给你一点启示。
用一个\(f\)数组记录每个地方最多能够游览的地方,数,初始化为1。
首先,我就将各个地方按照\(happy\)值升序排个序,接下来,我就安排序后的顺序,一个一个做。找到能当前节点的所有点,判断是否满足\(happy\)值比当前节点大,如果是,就更新当前节点的\(f\)数组\((f_x=max(f_x,f_t+1))\)。最后,在\(f\)数组中找一个最大的数,就是答案。
代码
#include<bits/stdc++.h>
#define maxn 100039
#define maxm 1000039
#define max(x,y) (x>y?x:y)
using namespace std;
int n,m;
struct zj{
int happy,num,ans=1;//happy值,原来的编号,答案
}f[maxn];
int nex[maxm],to[maxm],head[maxn],k;
void add(int a,int b)//链式前向星
{
to[k]=b;
nex[k]=head[a];
head[a]=k++;
return;
}
bool cmp(const zj &x,const zj &y)
{
return x.happy<y.happy;
}
int main()
{
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&f[i].happy),f[i].num=i;
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
//题中说是双向边
}
int w[maxn];//记录原来节点的排序后位置
sort(a+1,a+1+n,cmp);//排序
for(int i=1;i<=n;i++)
w[f[i].num]=i;//记录位置
int ans=0;//最终答案
for(int i=1;i<=n;i++)
{
int pos=head[f[i].num],t=0;
while(pos!=-1)
{
if(f[w[to[pos]]].happy<f[i].happy)//满足题中条件
t=max(t,f[i].ans+f[w[to[pos]]].ans);//更新当前节点的答案
pos=nex[pos];
}
t=max(t,a[i].ans);
a[i].ans=t;
ans=max(ans,t);//更新最终答案
}
if(ans>1000000007)cout<<"infinity";
else cout<<ans;
return 0;
}