P2446 [SDOI2010]大陆争霸
Posted Jozky86
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
#else
startTime = clock(); //计时开始
freopen("landcraft.in","r",stdin);
#endif
}
void Time_test(){
#ifdef ONLINE_JUDGE
#else
endTime = 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();
}
以上是关于P2446 [SDOI2010]大陆争霸的主要内容,如果未能解决你的问题,请参考以下文章