P2446 [SDOI2010]大陆争霸
题意:
n个点,m个边,wi为每个边的边权,对于每个点i,其被l个点保护着,也就是如果保护其的点没有被破坏,点i无法被破坏(也无法经过其前往其他点)。现在从1出兵(无限数量),问破坏点n的最短时间
题解:
很明显这个题跟最短路有关,对于每个点,有这几种状态:是否保护,是否已经到达
因为如果我们跑最短路,跑出来的结果并不是,因为有些点受保护的情况,实际到达时间要被推迟(直到保护他的点也被破坏)
我们用now[u]表示点u被破坏的时间,arrive[u]表示u无人保护的时刻(如果一开始就无人保护,默认值为0),dis[u]表示路径上到达u的时间
对于now[u]应该取dis[u]和arrive[u]的最大值,因为u被破坏需要可达(不被保护)且已经到达(路径距离)
dis[u]最短路维护,arrive[u]怎么维护呢?
arrive[u]记录的其实是保护u的点x,x被破坏的最大值。所以如果u被x保护,我们就从x到u建一个边(无向边),在跑最短路过程中,不断更新arrive[u],arrive[u]=max(now[x])
详细可以见代码
代码:
#include<bits/stdc++.h>
#define debug(a,b) printf("%s = %d\n",a,b);
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
clock_t startTime, endTime;
//Fe~Jozky
const ll INF_ll=1e18;
const int INF_int=0x3f3f3f3f;
inline ll read(){ll s=0,w=1ll;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')w=-1ll;ch=getchar();}while(ch>='0'&&ch<='9') s=s*10ll+((ch-'0')*1ll),ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);return s*w;
}
void rd_test(){#ifdef ONLINE_JUDGE#elsestartTime = clock(); //计时开始freopen("landcraft.in","r",stdin);#endif
}
void Time_test(){#ifdef ONLINE_JUDGE#elseendTime = clock(); //计时结束printf("\n运行时间为:%lfs\n",(double)(endTime - startTime) / CLOCKS_PER_SEC);#endif
}
const int maxn=1e6+9;
struct Edge
{int u,v,w,next;
}e[maxn];
int head[maxn],cnt,n,m,s,vis[maxn],dis[maxn],pre[maxn];
int ind[maxn],arrive[maxn],now[maxn];
struct node
{int w,now;inline bool operator <(const node &x)const//重载运算符把最小的元素放在堆顶(大根堆){return w>x.w;//这里注意符号要为'>'}
};
priority_queue<node>q;
inline void add(int u,int v,int w)
{e[++cnt].u=u;//这句话对于此题不需要,但在缩点之类的问题还是有用的e[cnt].v=v;e[cnt].w=w;e[cnt].next=head[u];//存储该点的下一条边head[u]=cnt;//更新目前该点的最后一条边(就是这一条边)
}
vector<int>vec[maxn];
void dijkstra()
{for(int i=1;i<=n;i++){dis[i]=INF_int;arrive[i]=0;}dis[s]=arrive[s]=0;//赋初值q.push((node){0,s});int u,v;while(!q.empty())//堆为空即为所有点都更新{node x=q.top();q.pop();u=x.now;//记录堆顶(堆内最小的边)并将其弹出if(vis[u]) continue; //没有遍历过才需要遍历vis[u]=1;now[u]=max(dis[u],arrive[u]);//到达u的时间时间 for(int i=head[u];i;i=e[i].next)//更新所有dis[v] {v=e[i].v;if(dis[v]>now[u]+e[i].w){dis[v]=now[u]+e[i].w;if(!ind[v]){//如果这个点没有被保护 pre[v]=u;//松弛操作now[v]=max(dis[v],arrive[v]);q.push((node){max(dis[v],arrive[v]),v});//把新遍历到的点加入堆中}}}//开始摧毁点u for(int i=0;i<vec[u].size();i++){v=vec[u][i];ind[v]--;arrive[v]=max(arrive[v],now[u]);if(!ind[v]){now[v]=max(dis[v],arrive[v]);q.push((node){now[v],v}); }}}
}int main()
{rd_test();cin>>n>>m;s=1; for(int i=1;i<=m;i++){int x,y,z;x=read(),y=read(),z=read();add(x,y,z);}for(int i=1;i<=n;i++){int l=read();if(l==0)continue;for(int j=1;j<=l;j++){int x=read(); ++ind[i];vec[x].push_back(i);//vec[i].push_back(x);//add(x,i,0);}}dijkstra();cout<<now[n];//Time_test();
}