[CF346D]Robot Control

看来我果然还是太菜,只能看看思路才能AC

  • 题意

    自己查...

  • solution

    设dp[x]为从x到t最小需要控制次数

    对于一个点,我们有两种选择:控制,或者不控制

    基于这个,dp方程或许很好推: \(dp[now]=min(max{dp[to]},min{dp[to]}+1)\) to为从x点所能到达的所有点

    那么问题来了,怎么更新dp值?

    因为图很复杂,你用来更新其他点的点,可能又会被其他点更新(即有其他策略),

    所以我们要采用一种类似spfa的方法,把更新过的点推进队列.

    如何更新:对于一个点,我们用它的值来更新原图上能直接到达它的点的min{dp[to]}+1,然后用原图上它能到达的点的值来更新它的max

    而且我们要从t倒着搜到s,所以我们要建个反向图跑spfa

    但是还有一个问题,我们不能让机器人boom掉

    其实这个不难,因为机器人不走回路肯定比走回路优,所以dp避免了boom的情况

    贴个图理解一下

    我们在t这一点用dpt来更新dp[3]使dp[3]=1(min{dp[to]}+1)

    在3这一点用dp[3]来更新dp[2]使dp[2]=2(min{dp[to]}+1)

    同在3这一点,我们发现此时max{dp[to]}=dp[2]=2,不能更新dp[3]

    但在2这一点,max{dp[to]}=dp[3]=1,把dp[2]更新成2

    dp更新的流程就是这样.

    • code
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
#include<queue>
#define N 1000005
using namespace std;
vector<int> G[N],G2[N];
int f[N];
bool vis[N];
int n,m,s,t;
queue<int> q;
int main(){  
 scanf("%d%d",&n,&m);
 for(int i=1;i<=m;i++){
   int a,b;
   scanf("%d%d",&a,&b);
   G[a].push_back(b);
   G2[b].push_back(a);
   }
 scanf("%d%d",&s,&t);
 memset(f,0X3f,sizeof f);
 memset(vis,false,sizeof vis);
 q.push(t);
 f[t]=0;
 vis[t]=1; 
 while(!q.empty()){
   int now=q.front();
   q.pop();
   vis[now]=0;
   for(int i=0;i<G2[now].size();i++){
     int to=G2[now][i];
     if(f[to]>f[now]+1){
       f[to]=f[now]+1;
       if(!vis[to]){
         vis[to]=true;
         q.push(to);
         }
       }
     }
   int plk=0;
   for(int i=0;i<G[now].size();i++)plk=max(plk,f[G[now][i]]);
   if(plk<f[now]){
     f[now]=plk;
     if(!vis[now]){
       vis[now]=true;
       q.push(now);
       } 
     }
   }
 if(f[s]==0X3f3f3f3f)cout<<-1;
 else cout<<f[s];
 }
posted @ 2019-03-05 14:11  stepsys  阅读(284)  评论(0编辑  收藏  举报

*/