DAG上的动态规划

UVA1025

分析:因为时间是单向流逝的,是天然的"序",所以影响决策的只有当前时间和所处的决策。dp[i][j],表示在第i分钟时,处于第j个车站,最少还需要多少等待时间,因此其等待时间就有站原地等待,乘坐从左到右的车,乘坐从右到左的车,三个状态来决定。

 1 #include "iostream"
 2 #include "cstdio"
 3 #include "cstring"
 4 #include "string"
 5 using namespace std;
 6 const int maxn=1000+100;
 7 const int maxm=10000+100;
 8 const int INF=1<<30;
 9 int n,T,m1,m2;
10 int t[maxn],d[maxn],e[maxn];
11 int dp[maxm][60],vis[maxm][60][3];
12 int main()
13 {
14     int cas=0;
15     while(cin>>n)
16     {
17         if(n==0) break;
18         cin>>T;
19         memset(vis,0,sizeof(vis));
20         memset(dp,0,sizeof(dp));
21         memset(t,0,sizeof(t));
22         for(int i=1;i<n;i++)
23             cin>>t[i];
24         cin>>m1;
25         for(int i=1;i<=m1;i++)
26             cin>>d[i];
27         cin>>m2;
28         for(int i=1;i<=m2;i++)
29             cin>>e[i];
30         //从左到右
31         for(int i=1;i<=m1;i++){
32             int cnt=d[i];
33             for(int j=1;j<=n;j++){
34                 vis[cnt][j][0]=1;
35                 cnt+=t[j];
36             }
37         }
38         //从右到左
39         for(int i=1;i<=m2;i++){
40             int res=e[i];
41             for(int j=n;j>=1;j--){
42                 vis[res][j][1]=1;
43                 res+=t[j-1];
44             }
45         }
46 
47         for(int i=1;i<n;i++) dp[T][i]=INF;
48         dp[T][n]=0;
49         for(int i=T-1;i>=0;i--){
50             for(int j=1;j<=n;j++){
51                 dp[i][j]=dp[i+1][j]+1;
52                 if(j<n&&vis[i][j][0]&&(i+t[j]<=T))   //从左到右
53                     dp[i][j]=min(dp[i][j],dp[i+t[j]][j+1]);
54                 if(j>1&&vis[i][j][1]&&(i+t[j-1]<=T))
55                     dp[i][j]=min(dp[i][j],dp[i+t[j-1]][j-1]);
56             }
57         }
58         printf("Case Number %d: ",++cas);
59         if(dp[0][1]>=INF)  cout<<"impossible"<<endl;
60         else  cout<<dp[0][1]<<endl;
61 
62     }
63     return 0;
64 }
View Code

 UVA437

分析:如果j能够放在i上面,从i向j连边,最后求最大高度,dfs(i)表示从第i个开始的最长距离,注意处理三个长方体三个不同面的技巧

 1 #include "iostream"
 2 #include "cstdio"
 3 #include "cstring"
 4 #include "string"
 5 using namespace std;
 6 const int maxn=100;
 7 int n;
 8 struct Node{
 9     int x,y,z;
10 };
11 Node p[maxn];
12 int g[maxn][maxn];
13 bool judge(int a,int b){
14     if((min(p[a].x,p[a].y)>min(p[b].x,p[b].y))&&(max(p[a].x,p[a].y)>max(p[b].x,p[b].y)))
15         return true;
16     return false;
17 }
18 int dp[maxn];
19 int dfs(int i){
20     int& ans=dp[i];
21     if(ans!=-1)  return ans;
22     ans=p[i].z;
23     for(int j=1;j<=n;j++){
24         if(g[i][j])
25             ans=max(ans,dfs(j)+p[i].z);
26     }
27     return ans;
28 }
29 int main()
30 {
31     //freopen("a.txt","r",stdin);
32     //freopen("a.out","w",stdout);
33     int cas=0;
34     while(cin>>n)
35     {
36         if(n==0) break;
37         for(int i=1;i<=n;i++){
38             cin>>p[i].x>>p[i].y>>p[i].z;
39             p[i+n].x=p[i].y,p[i+n].y=p[i].z,p[i+n].z=p[i].x;
40             p[i+2*n].x=p[i].z,p[i+2*n].y=p[i].x,p[i+2*n].z=p[i].y;
41         }
42         n*=3;
43         memset(g,0,sizeof(g));
44         for(int i=1;i<=n;i++){
45             for(int j=1;j<=n;j++){
46                 if(judge(i,j))
47                     g[i][j]=1;
48             }
49         }
50         memset(dp,-1,sizeof(dp));
51         int ans=0;
52         for(int i=1;i<=n;i++){
53             ans=max(ans,dfs(i));
54         }
55         printf("Case %d: maximum height = ",++cas);
56         cout<<ans<<endl;
57     }
58 }
View Code

 UVA1347

分析:根据坐标是按照x排序的,所以这个问题肯定是个单向的,即一次不可能先选择i+2,再选择i+1。所以我们设dp[i][j]为已经选取了1-max(i,j)当中的所有元素,同时第一个位于i,第二个位于j时,还需要在走的最少距离。则dp[i][j]必然来自于dp[i+1][j](第一个走i+1),dp[i+1][i](第二个走i+1),两种决策当中的最小值,处理一下边界即可,非常经典的一个题

 1 #include "iostream"
 2 #include "cstdio"
 3 #include "cstring"
 4 #include "string"
 5 #include "cmath"
 6 using namespace std;
 7 const int maxn=10000;
 8 const double INF=1<<30;
 9 struct Node
10 {
11     int x,y;
12 };
13 Node p[maxn];
14 double dp[maxn][maxn];
15 int n;
16 double dist(int x1,int y1,int x2,int y2){
17     int num=(x1-x2)*(x1-x2);
18     int ans=(y1-y2)*(y1-y2);
19     double res=sqrt((double)num+(double)ans);
20     return res;
21 }
22 int main()
23 {
24     while(cin>>n){
25         if(n==0)  break;
26         for(int i=1;i<=n;i++){
27             cin>>p[i].x>>p[i].y;
28         }
29         for(int i=1;i<=n;i++)
30             dp[n][i]=dist(p[i].x,p[i].y,p[n].x,p[n].y);
31         for(int i=1;i<=n;i++){
32             dp[n-1][i]=dist(p[n-1].x,p[n-1].y,p[n].x,p[n].y)+dist(p[i].x,p[i].y,p[n].x,p[n].y);
33         }
34         for(int i=n-2;i>=2;i--){
35             for(int j=1;j<i;j++)
36                 dp[i][j]=min(dp[i+1][j]+dist(p[i+1].x,p[i+1].y,p[i].x,p[i].y),dp[i+1][i]+dist(p[j].x,p[j].y,p[i+1].x,p[i+1].y));
37         }
38         double res=dist(p[1].x,p[1].y,p[2].x,p[2].y)+dp[2][1];
39         printf("%.2f\n",res);
40     }
41     return 0;
42 }
View Code

 

转载于:https://www.cnblogs.com/wolf940509/p/7220145.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值