[codeforces#438 E题]Policeman and a Tree

来源:互联网 发布:域名不合法是怎么回事 编辑:程序博客网 时间:2024/06/07 12:45

基于边的树形DP+DP转移一个神奇的二分。

二分要从罪犯的角度去理解,之前一直在纠结一个警察和罪犯的极大极小博弈,没想到可以有这么一个神奇的二分。

写完AC,但感觉理解得不够深刻。

#include<stdio.h>#include<string.h>#include<vector>#include<algorithm>using namespace std;#define INF 0x7f000000#define N 55struct EDGE{  int u,v,w;  EDGE(int u=0,int v=0,int w=0):u(u),v(v),w(w){}};vector<EDGE> e;vector<int> g[N];int f[N*2][N][N];int n,m;int ccnt[N];bool isleaf[N];int st;void read(){  scanf("%d",&n);  for (int i=1;i<n;i++){    int u,v,w;    scanf("%d%d%d",&u,&v,&w);    e.push_back(EDGE(u,v,w));    e.push_back(EDGE(v,u,w));    g[u].push_back(e.size()-2);    g[v].push_back(e.size()-1);  }  scanf("%d",&st);  scanf("%d",&m);  memset(ccnt,0,sizeof(ccnt));  for (int i=1;i<=m;i++){    int x;    scanf("%d",&x);    ccnt[x]++;  }  memset(isleaf,0,sizeof(isleaf));  for (int i=1;i<=n;i++)    if (g[i].size()==1)      isleaf[i]=true;}int dfs(int u,int p){  for (int i=0;i<g[u].size();i++){    EDGE ed=e[g[u][i]];    if (ed.v==p)continue;    ccnt[u]+=dfs(ed.v,u);  }  //printf("ccnt[%d]=%d\n",u,ccnt[u]);  return ccnt[u];}int dp(int eid,int s,int s2){ //沿着eid走  int &fval=f[eid][s][s2];  if (fval<INF) return fval;  if (s==0) return 0;  if (s2==0) exit(-2);  EDGE ed=e[eid];  int u=ed.u;int v=ed.v;int w=ed.w;  //到达叶子节点//抓住s2个罪犯,往回走  if (isleaf[v]){     fval=w+dp(eid^1,s-s2,s-s2);     //printf("fval=%d\n",fval);     return fval;  }  //非叶子节点  //神奇的二分,找到T,表示警察能抓到所有罪犯最小时间  int l=1,r=N*N*N;  while(l<r){     int T=(l+r)/2;     int sum=0;  //不让警察在T时间内抓住的最大罪犯个数     for (int i=0;i<g[v].size();i++){            int v2=e[g[v][i]].v;            int w2=e[g[v][i]].w;            if (v2==u) continue; //不走回头            //找到尽量大的b,使得当走e[g[u][i]]这条边,可以在<=T的时间内抓住所有罪犯            int b;            for(b=1;b<=s2;b++){                if (dp(g[v][i],s,b)<=T)                    break;            }            if (b>s2)                sum=s2;            else               sum+=b-1;            if (sum>=s2) break;     }     if (sum>=s2) //存在一种方案使得警察无法在T时间内抓到所有人        l=T+1;     else        r=T;  }  fval=w+l;  return fval;}int main(){  read();  dfs(st,0);  memset(f,127,sizeof(f));  int ans=INF;  for (int i=0;i<g[st].size();i++){    EDGE ed=e[g[st][i]];    if (ccnt[ed.v])        ans=min(ans,dp(g[st][i],m,ccnt[ed.v]));  }  printf("%d\n",ans);  //printf("%d",dp(3,1,1));  return 0;}


原创粉丝点击