题目概述
有
n
个点
解题报告
刚开始以为是拓扑,之后发现显然不是,因为一个点没被摧毁之前是不能访问的。
所以SPFA也不能用了,只剩下Dijkstra。记录
dis[0][i]
表示到
i
点的最短时间,
这么贪心应该是对的吧……
示例程序
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fr first
#define sc second
#define mp make_pair
using namespace std;
typedef long long LL;typedef pair<int,LL> data;
const int maxn=3000,maxm=1e6;
int n,m,f[maxn+5];LL dis[2][maxn+5];bool vis[maxn+5];
int E,lnk[2][maxn+5],son[maxm+5],nxt[maxm+5],w[maxm+5];
int si;data Heap[maxn+maxm+5];
inline void Add(int x,int y,int z) {son[++E]=y;w[E]=z;nxt[E]=lnk[0][x];lnk[0][x]=E;}
inline void Add(int x,int y) {son[++E]=y;nxt[E]=lnk[1][x];lnk[1][x]=E;}
inline bool cmp(const data &a,const data &b) {return a.sc>b.sc;}
#define dis(x) max(dis[0][x],dis[1][x])
#define Push(x) Heap[++si]=(x),push_heap(Heap+1,Heap+1+si,cmp)
#define Pop() pop_heap(Heap+1,Heap+1+si--,cmp)
void Dij()
{
memset(dis[0],63,sizeof(dis[0]));dis[0][1]=dis[1][1]=0;Push(mp(1,dis(1)));
while (si)
{
int k=Heap[1].fr;while (vis[k]) Pop(),k=Heap[1].fr;
if (k==n) break;vis[k]=true;LL MIN=Heap[1].sc;Pop();
for (int j=lnk[0][k];j;j=nxt[j]) if (!vis[son[j]])
{
int u=son[j];dis[0][u]=min(dis[0][u],MIN+w[j]);
if (!f[u]) Push(mp(u,dis(u)));
}
for (int j=lnk[1][k];j;j=nxt[j]) if (!vis[son[j]])
{
int u=son[j];dis[1][u]=max(dis[1][u],MIN);f[u]--;
if (!f[u]) Push(mp(u,dis(u)));
}
}
}
int main()
{
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1,x,y,z;i<=m;i++) scanf("%d%d%d",&x,&y,&z),Add(x,y,z);
for (int i=1,x;i<=n;i++)
{scanf("%d",&f[i]);for (int t=1;t<=f[i];t++) scanf("%d",&x),Add(x,i);}
return Dij(),printf("%lld\n",dis(n)),0;
}