noi 2008 设计路线 动态规划

题意:Z 国坐落于遥远而又神奇的东方半岛上,在小Z 的统治时代公路成为这里主要的交通手段。Z 国共有n 座城市,一些城市之间由双向的公路所连接。非常神奇的是Z 国的每个城市所处的经度都不相同,并且最多只和一个位于它东边的城市直接通过公路相连。Z 国的首都是Z 国政治经济文化旅游的中心,每天都有成千上万的人从Z 国的其他城市涌向首都。 为了使Z 国的交通更加便利顺畅,小Z 决定在Z 国的公路系统中确定若干条规划路线,将其中的公路全部改建为铁路。 我们定义每条规划路线为一个长度大于1 的城市序列,每个城市在该序列中最多出现一次,序列中相邻的城市之间由公路直接相连(待改建为铁路)。并且,每个城市最多只能出现在一条规划路线中,也就是说,任意两条规划路线不能有公共部分。 当然在一般情况下是不可能将所有的公路修建为铁路的,因此从有些城市出发去往首都依然需要通过乘坐长途汽车,而长途汽车只往返于公路连接的相邻的城市之间,因此从某个城市出发可能需要不断地换乘长途汽车和火车才能到达首都。 我们定义一个城市的“不便利值”为从它出发到首都需要乘坐的长途汽车的次数,而Z 国的交通系统的“不便利值”为所有城市的不便利值的最大值,很明显首都的“不便利值”为0。小Z 想知道如何确定规划路线修建铁路使得Z 国的交通系统的“不便利值”最小,以及有多少种不同的规划路线的选择方案使得“不便利值”达到最小。当然方案总数可能非常大,小Z 只关心这个天文数字mod Q 后的值。 注意:规划路线1-2-3 和规划路线3-2-1 是等价的,即将一条规划路线翻转依然认为是等价的。两个方案不同当且仅当其中一个方案中存在一条规划路线不属于另一个方案。

 

思路:这是一棵树。

知道这个就很容易想到树型DP。但是状态的设计十分的讲究。

首先 我们如果这样设置状态

F[0][i][j]表示i这棵子树,不便利值不超过j的时候,且i与他的儿子最多只连了一条边的方案总数。

F[1][i][j]表示i这棵子树,不便利值不超过j的时候,且i与他的儿子连了两条边的方案总数。

则F[0][i][j]=Sum{(F[0][k][j])*(F[0][x1][j-1]+F[1][x1][j-1])*(F[0][x2][j-1]+F[1][x2][j-1])……}+(F[0][x1][j-1]+F[1][x1][j-1])*……   其中k为枚举的儿子

F[1][i][j]=Sum{F[0][k1][j]*F[0][k2][j]*(F[0][x1][j-1]+F[1][x1][j-1])*(F[0][x2][j-1]+F[1][x2][j-1])….}其中k1,k2都是枚举的儿子。

我们发现,这样转移需要枚举儿子,且复杂度可能高达O(n^2)。所以是行不通的。

我们将状态设计得复杂点。

F[0][i][j]表示i这棵子树,不便利值不超过j的时候,且i与他的儿子没连边的方案总数。

F[1][i][j]表示i这棵子树,不便利值不超过j的时候,且i与他的儿子连了一条边的方案总数。

F[1][i][j]表示i这棵子树,不便利值不超过j的时候,且i与他的儿子连了两条边的方案总数。

假设现在我们一个儿子一个儿子的转移。现在F[0..2][x]已临时算出。

则F[2][i][j]=F[1][i][j]*F[0\1][son][j]+F[2][i][j]*F[0\1\2][son][j-1]

F[1][i][j]=F[0][i][j]*F[0\1][son][j]+F[1][i][j]*F[0\1\2][son][j-1]

F[0][i][j]=F[0][i][j]*F[0\1\2][son][j-1]

其中\的意思是将那几个求和。

这样可在O(n)的时间完成转移。

转自:http://zzlqxbms.diandian.com/post/2010-07-05/14089207

  1 #include<iostream>
  2 #include<cmath>
  3 #include<cstring>
  4 #include<cstdio>
  5 using namespace std;
  6 #define MAXN 100001
  7 long long dp[3][MAXN][11];
  8 bool use[3][MAXN][11];
  9 int n,m,MOD;
 10 struct node
 11 {
 12     int num;
 13     node *next;
 14 };
 15 node memo[2*MAXN],*graph[MAXN];
 16 int top=0;
 17 int Q[MAXN],father[MAXN];
 18 void add(int x,int y)
 19 {
 20     node *p=&memo[top++];
 21     p->num=y; p->next=graph[x]; graph[x]=p;
 22     p=&memo[top++];
 23     p->num=x; p->next=graph[y]; graph[y]=p;
 24 }
 25 void bfs()
 26 {
 27     father[1]=0;
 28     int left,right;
 29     Q[left=right=1]=1;
 30     while(left<=right)
 31     {
 32         int u=Q[left++];
 33         for(node *p=graph[u];p;p=p->next)
 34         if(p->num!=father[u])
 35             Q[++right]=p->num,father[p->num]=u;
 36     }
 37 }
 38 
 39 void solve()
 40 {
 41     int i,j,u,v;
 42     for(i=n;i>0;i--)
 43     {
 44         //cout<<i<<endl;
 45         u=Q[i];
 46         dp[0][u][0]=1;
 47         use[0][u][0]=1;
 48         for(node *p=graph[u];p;p=p->next)
 49         if(p->num!=father[u])
 50         {
 51             v=p->num;
 52             use[2][u][0]=use[1][u][0]&(use[0][v][0]|use[1][v][0]);
 53             use[1][u][0]=use[0][u][0]&(use[0][v][0]|use[1][v][0]);
 54             use[0][u][0]=0;
 55             dp[2][u][0]=dp[1][u][0]*(dp[0][v][0]+dp[1][v][0])%MOD;
 56             dp[1][u][0]=dp[0][u][0]*(dp[0][v][0]+dp[1][v][0])%MOD;
 57             dp[0][u][0]=0;
 58         }
 59         for(j=1;j<=10;j++)
 60         {
 61             use[0][u][j]=1;
 62             dp[0][u][j]=1;
 63             for(node *p=graph[u];p;p=p->next)
 64             if(p->num!=father[u])
 65             {
 66                 v=p->num;
 67                 use[2][u][j]=(use[1][u][j]&(use[0][v][j]|use[1][v][j]))|((use[0][v][j-1]|use[1][v][j-1]|use[2][v][j-1])&use[2][u][j]);
 68                 use[1][u][j]=(use[0][u][j]&(use[0][v][j]|use[1][v][j]))|((use[0][v][j-1]|use[1][v][j-1]|use[2][v][j-1])&use[1][u][j]);
 69                 use[0][u][j]=(use[0][v][j-1]|use[1][v][j-1]|use[2][v][j-1])&use[0][u][j];
 70             
 71                 dp[2][u][j]=(dp[1][u][j]*(dp[0][v][j]+dp[1][v][j])%MOD+(dp[0][v][j-1]+dp[1][v][j-1]+dp[2][v][j-1])%MOD*dp[2][u][j])%MOD;
 72                 dp[1][u][j]=(dp[0][u][j]*(dp[0][v][j]+dp[1][v][j])%MOD+(dp[0][v][j-1]+dp[1][v][j-1]+dp[2][v][j-1])%MOD*dp[1][u][j])%MOD;
 73                 dp[0][u][j]=(dp[0][v][j-1]+dp[1][v][j-1]+dp[2][v][j-1])%MOD*dp[0][u][j]%MOD;
 74             }
 75         }
 76     }
 77     for(j=0;j<=10;j++)
 78     {
 79         if(use[0][1][j]!=0||use[1][1][j]!=0||use[2][1][j]!=0)
 80                     break;
 81     }
 82     printf("%d\n",j);
 83     printf("%lld\n",(dp[0][1][j]+dp[1][1][j]+dp[2][1][j])%MOD);
 84 }
 85 int main()
 86 {
 87     int i,x,y;
 88     memset(use,0,sizeof(use));
 89     memset(dp,0,sizeof(dp));
 90     memset(graph,0,sizeof(graph));
 91     scanf("%d%d%d",&n,&m,&MOD);
 92     for(i=1;i<=m;i++)
 93     {
 94         scanf("%d%d",&x,&y);
 95         add(x,y);
 96     }
 97     if(m!=n-1)
 98     {
 99         printf("-1\n-1\n");
100         return 0;
101     }
102     bfs();
103     solve();
104     return 0;
105 }

转载于:https://www.cnblogs.com/myoi/archive/2012/07/17/2594772.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值