Description
狮鹫是联盟的主要交通工具,在艾泽拉斯的土地上散布着n个狮鹫站点,有m条有向的飞行线路,也就是构成了一张n个点m条边的有向图。
这m条线路被分成了c种等级,对于其中的第i种等级,只有声望达到了w i 才能乘坐狮鹫飞过这条线路。
小C现在在暴风城(1号点),他要赶到暗月马戏团(n号点)参加他学长的电音表演。作为一个喜欢藏锋的健美先生,初始时他声望为0。但他实在是太健美了,以至于他每乘坐一次狮鹫(即经过一条边)就能使他的声望 +1 。
为了更好地藏锋,小C不会通过其他方法来提升声望。小C不喜欢步行,也不会开传送门,所以他不会通过除乘坐狮鹫以外的其他方法来到达另一个站点。现在他想知道是否能到达,如果能,他还想知道他最少要经过多少条边才能到达.
Input
从文件griffin.in中读入数据.
第一行三个整数n,m,c.
接下来m行,每行三个整数u,v,lv,表示有一条u到v的线路,等级为lv. 接下来一行c个整数,第i个表示w i .
Output
输出到文件griffin.out中.
若不能到达输出Impossible。
否则输出一个整数表示他最少要经过的边数。
Sample Input
输入1:
3 2 2
1 2 1
2 3 2
0 2
输入2:
3 3 2
1 2 1
2 1 1
2 3 2
0 2
Sample Output
输出1:
Impossible
输出2:
4
Data Constraint
对于所有数据,有2≤n≤180,1≤c≤50,0≤m≤4×10^4 ,0≤wi≤wi+1≤10^9 .
可 能 有 重 边 或 自 环.
• subtask1(17%), c = 1.
• subtask2(24%), w i ≤ 10^3 .
• subtask3(27%), n ≤ 40.
• subtask4(32%), 没有特殊的约定.
题解
注意观察就可以发现,在
的时候,整张图可以走的边是相同的,
所以,整张图的边改变就只有c次。
将每个时刻可以到达的点的0/1状态看成以行向量,
中间的转移矩阵就是图中有哪些边。
每走也不就是乘上一次中间这个转移矩阵,
而这个转移矩阵在某些连续的时刻是不变的,
那么就可以有快速幂来处理。
具体做法:从小到大枚举边的等级,
将符合当前等级的边加入转移矩阵,
类似倍增的样子,求出这个矩阵的2的次幂次方,
先判断在到达下一个等级之前是否能到达n(为了方便处理,提前加入一条等级最低n的自环)。
如果不可以,就直接跳到下一个等级,
否则就说明在这个等级的某个时刻就已经到达n了。
从大到小枚举这个矩阵的2的次幂次方,
如果行向量乘上这个矩阵没有到达n,就将其乘上,并记录答案。
最后答案就+1好了,这个过程很类似倍增求lca。
算一下时间复杂度
好像有点大,
那么就用bitset优化。
code
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<bitset>
#define G getchar
using namespace std;
char ch;
void read(int &n)
{
int w;
for(ch=G();(ch<'0' || ch>'9') && ch!='-';ch=G());
if(ch=='-')w=-1,ch=G();else w=1;
for(n=0;'0'<=ch && ch<='9';ch=G())n=(n<<1)+(n<<3)+ch-48;
n=n*w;
}
const int N=203;
struct node
{
int x,y,v;
}a[N*N];
int n,m,c,w[N],ans,pos,z[33],t;
bool pd;
bitset<N>f[33][N],A[N],B,p,q;
bool cmp(node a,node b)
{
return a.v<b.v;
}
void mul(int x)
{
for(register int i=1;i<=n;i++)
f[x][i].reset();
for(register int i=1;i<=n;i++)
for(register int j=1;j<=n;j++)
if(f[x-1][i][j])f[x][i]|=f[x-1][j];
}
void mul1(int x)
{
for(int i=1;i<=n;i++)
B[i]=q[i];
q.reset();
for(register int i=1;i<=n;i++)
if(B[i])q|=f[x][i];
}
int main()
{
freopen("griffin.in","r",stdin);
freopen("griffin.out","w",stdout);
z[0]=1;
for(int i=1;i<33;i++)
z[i]=z[i-1]<<1;
read(n);read(m);read(c);
for(int i=1;i<=m;i++)
read(a[i].x),read(a[i].y),read(a[i].v);
for(int i=1;i<=c;i++)
read(w[i]);
m++;a[m].x=a[m].y=n;
sort(a+1,a+1+m,cmp);
p[pos=1]=1;w[c+1]=w[c]+m+n;
for(int k=0;k<=c;k++)
{
for(;a[pos].v==k;pos++)f[0][a[pos].x][a[pos].y]=1;
t=w[k+1]-w[k];
for(int i=1;z[i]<=t;i++)mul(i);
q=p;
for(int i=0;z[i]<=t;i++)
if(t&z[i])mul1(i);
if(q[n])
{
pd=1;
for(int i=29;i>=0;i--)
if(z[i]<=t)
{
q=p;
mul1(i);
if(!q[n])
{
p=q;
ans|=z[i];
}
}
ans+=w[k];
break;
}
else p=q;
}
if(pd)printf("%d\n",ans+1);else puts("Impossible");
return 0;
}