UVALive 3683 A Scheduling Problem(树形DP)

    xiaoxiao2021-03-25  61

    题目链接:点击打开链接

    题目中给出了一个关键的提示:设这棵树的最长链的点个数为K的时候,答案为K或者K+1

    那么可以这么考虑·;验证答案能否为K,能的话答案就是K,否则答案就为K+1。

    那么问题便转换为,给那些无向边以方向,问能否使最长链的点的个数为K。

    首先先预处理出最长链的点的个数K以及其中一条最长链的第一个点D。

    在这里为了方便起见,人为地定义了每个点的深度d,并规定点D的深度为1,所有有向边中被指向的点的深度必定大于指向它的点的深度。

    那么问题便进一步转换为,能否给树中的无向边方向使得所有的点的深度均在区间[1,K]内。

    将树拉为以D为根的树,便可以进行dp了。

    设dp[pos][c]为,当点pos的深度为K的时候,以点pos为根的子树能否满足条件。

    状态转移也能够很容易的得到:

    设pos的一个儿子为son,

    如果pos指向son的话,其儿子可能的状态只有dp[son][c+j](j.>0,下同);

    如果son指向pos的话,其儿子可能的状态只有dp[son][c-j];

    如果pos跟son之间的连边是无向边的话,其儿子可能的状态就有dp[son][c+j]和dp[son][c-j];

    当pos的儿子中有一个dp值为真的时候其dp值便为真,否则便为假。

    记忆化搜索一波就可以了。

    代码如下:

    #include<bits/stdc++.h> using namespace std; struct edge { int u,v; int w;//0:u->v 1:u--v 2:u<-v edge(int uu=0,int vv=0,int ww=0):u(uu),v(vv),w(ww){} }; vector<edge> e[2005]; int MaxD[2005]; bool vis[2005][2005]; bool dp[2005][2005]; int n,K; void input(int p) { n=p; char s[10]; do { n=max(n,p); while(scanf("%s",s)==1) { if(s[0]=='0')break; int pp=0; char c='k'; int len=strlen(s); for(int i=0;i<len;i++) { if(s[i]>='0'&&s[i]<='9') { pp*=10; pp+=(s[i]-'0'); } else c=s[i]; } n=max(n,pp); if(c=='k') { e[p].push_back(edge(p,pp,1)); e[pp].push_back(edge(pp,p,1)); } else if(c=='d') { e[p].push_back(edge(p,pp,0)); e[pp].push_back(edge(pp,p,2)); } else { e[p].push_back(edge(p,pp,2)); e[pp].push_back(edge(pp,p,0)); } } scanf("%d",&p); }while(p!=0); } void Pre_dfs(int pos) { if(MaxD[pos]!=-1)return; MaxD[pos]=1; for(int i=0;i<e[pos].size();i++) { edge &p=e[pos][i]; if(p.w!=0)continue; Pre_dfs(p.v); MaxD[pos]=max(MaxD[pos],MaxD[p.v]+1); } } bool dfs(int prt,int pos,int c) { if(c<1||c>K)return false; if(vis[pos][c])return dp[pos][c]; vis[pos][c]=true; dp[pos][c]=true; for(int i=0;i<e[pos].size();i++) { edge &p=e[pos][i]; if(p.v==prt)continue; if(p.w==0) { bool pans=false; for(int j=1;(!pans)&&c+j<=K;j++) pans=pans||dfs(pos,p.v,c+j); dp[pos][c]=dp[pos][c]&&pans; } else if(p.w==2) { bool pans=false; for(int j=1;(!pans)&&c-j>=1;j++) pans=pans||dfs(pos,p.v,c-j); dp[pos][c]=dp[pos][c]&&pans; } else { bool pans=false; for(int j=1;(!pans)&&c+j<=K;j++) pans=pans||dfs(pos,p.v,c+j); for(int j=1;(!pans)&&c-j>=1;j++) pans=pans||dfs(pos,p.v,c-j); dp[pos][c]=dp[pos][c]&&pans; } } return dp[pos][c]; } int main() { int p; while(scanf("%d",&p)==1&&p) { for(int i=1;i<=2000;i++) e[i].clear(); input(p); memset(MaxD,-1,sizeof(MaxD)); for(int i=1;i<=n;i++) Pre_dfs(i); int mx=1; for(int i=2;i<=n;i++) if(MaxD[i]>MaxD[mx]) mx=i; K=MaxD[mx]; memset(vis,0,sizeof(vis)); if(dfs(-1,mx,1))printf("%d\n",K); else printf("%d\n",K+1); } }

    转载请注明原文地址: https://ju.6miu.com/read-35279.html

    最新回复(0)