日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

vijos 1006 晴天小猪历险记之Hill——数字三角形的终极变化

發布時間:2023/11/27 生活经验 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 vijos 1006 晴天小猪历险记之Hill——数字三角形的终极变化 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目鏈接:https://vijos.org/p/1006

數字三角形原題看這里:http://www.cnblogs.com/huashanqingzhu/p/7326837.html

背景

在很久很久以前,有一個動物村莊,那里是豬的樂園(^_^),村民們勤勞、勇敢、善良、團結……
不過有一天,最小的小小豬生病了,而這種病是極其罕見的,因此大家都沒有儲存這種藥物。所以晴天小豬自告奮勇,要去采取這種藥草。于是,晴天小豬的傳奇故事便由此展開……

描述

這一天,他來到了一座深山的山腳下,因為只有這座深山中的一位隱者才知道這種藥草的所在。但是上山的路錯綜復雜,由于小小豬的病情,晴天小豬想找一條需時最少的路到達山頂,但現在它一頭霧水,所以向你求助。

山用一個三角形表示,從山頂依次向下有1段、2段、3段等山路,每一段用一個數字T(1<=T<=100)表示,代表晴天小豬在這一段山路上需要爬的時間,每一次它都可以朝左、右、左上、右上四個方向走。山是環形的。(**注意**:在任意一層的第一段也可以走到本層的最后一段或上一層的最后一段)。

晴天小豬從山的左下角出發,目的地為山頂,即隱者的小屋。

★★★**本題為vijos早年陳題,描述晦澀,現重新描述題面如下**★★★
有一個數字三角形,共nn行,依次編號為第一行,第二行至第nn行。其中第ii行有ii個數字,位置依次記為(i,1),(i,2)(i,1),(i,2)到(i,i)(i,i)。
現在從第nn層的第一個位置出發(即(n,1)),每一步移到相鄰的,且行編號小于或等于當前行編號的一個位置中,直到(1,1)結束,在不重復經過任何位置的情形下,路過的所有位置(包括端點)的對應數字之和最小。

下面詳細定義相鄰關系。
同一層內連續的兩個位置相鄰,特別的有每一層第一個位置與最后一個位置相鄰。
對于位置(i,j),它與(i-1,j-1)以及(i-1,j)相鄰,特別的(i,1)(i-1,i-1)相鄰,且(i,i)(i-1,1)相鄰。

格式

輸入格式

第一行有一個數n(2<=n<=1000),表示山的高度。

從第二行至第n+1行,第i+1行有i個數,每個數表示晴天小豬在這一段山路上需要爬的時間。

輸出格式

一個數,即晴天小豬所需要的最短時間。

樣例1

樣例輸入1

5
1
2 3
4 5 6
10 1 7 8
1 1 4 5 6

樣例輸出1

10

限制

各個測試點1s

提示

在山的兩側的走法略有特殊,請自己模擬一下,開始我自己都弄錯了……

來源

Sunnypig

算法分析:

參考:

http://blog.csdn.net/Little_Flower_0/article/details/47945611

https://vijos.org/p/1006/solution

http://www.cnblogs.com/candy99/p/5981533.html

?算法一:

建立圖,然后求最短路徑。(來源)

(從上往下建)

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <cstring>
 5 #include <cmath>
 6 #include <queue>
 7 using namespace std;
 8 typedef long long ll;
 9 const int N=1005*1005/2,INF=1e9+5;
10 inline int read(){
11     char c=getchar();int x=0,f=1;
12     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
13     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
14     return x*f;
15 }
16 int n,t[N],u,v,w;
17 inline int id(int i,int j){
18     return i*(i-1)/2+j;
19 }
20 struct edge{
21     int v,ne;
22 }e[N<<1];
23 int cnt=0,h[N];
24 inline void add(int u,int v){
25     cnt++;
26     e[cnt].v=v;e[cnt].ne=h[u];h[u]=cnt;
27 }
28 inline void ins(int u,int v){
29     add(u,v);add(v,u);
30 }
31 int d[N],inq[N];
32 queue<int> q;
33 void spfa(int s){
34     int m=id(n,n);
35     for(int i=1;i<=m;i++) d[i]=INF;
36     d[s]=0;
37     q.push(s);
38     while(!q.empty()){
39         int u=q.front();q.pop();
40         inq[u]=0;
41         for(int i=h[u];i;i=e[i].ne){
42             int v=e[i].v,w=t[u];
43             if(d[v]>d[u]+w){
44                 d[v]=d[u]+w;
45                 if(!inq[v]){inq[v]=1;q.push(v);}
46             }
47         }
48     }
49 }
50 int main(){
51     n=read();
52     for(int i=1;i<=n;i++){
53         if(i!=1) ins(id(i,1),id(i,i));
54         if(i<n&&i!=1){
55             add(id(i,i),id(i+1,1));
56             add(id(i,1),id(i+1,i+1));
57         }
58         for(int j=1;j<=i;j++){
59             t[id(i,j)]=read();
60             if(j<i) ins(id(i,j),id(i,j+1));
61             if(i<n) add(id(i,j),id(i+1,j)),add(id(i,j),id(i+1,j+1));            
62         }
63     }
64     spfa(id(1,1));
65     printf("%d",d[id(n,1)]+t[id(n,1)]);
66 }
View Code

或者參考下面的這一段代碼:

最短路很容易~
但是建圖有點麻煩~~
因為考慮到如果從一個點往上連邊的話
會有點小麻煩(可能不存在~)
那么我們可以從每一個點開始
每一個可以走到它的點向他連邊
即向下找往上連
如果是在一行的首位置或者末位置就有5種被走上來的方法
否則四種走法
這個需要很小心注意一個地方寫錯了就gg(調了半小時)
好坑的地方就是這里的右上方=上方....
害怕~
然后用個等差數列求和公式求出對應的頂標就好啦~

?代碼來源:https://vijos.org/p/1006/solution

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <algorithm>
  4 #include <cstring>
  5 #include <queue>
  6 using namespace std;
  7 
  8 const int MAXn=1005;
  9 const int MAXN=500501;
 10 const int MAXM=2500001;
 11 const int INF=(1<<30)-1;
 12 struct Edge
 13 {
 14     int to,w,next;
 15 }e[MAXM];
 16 int fisrt[MAXN];//Edges
 17 queue<int> q;
 18 int d[MAXN],in[MAXN];//SPFA
 19 int w[MAXn][MAXn];
 20 int l,n,tot;
 21 
 22 inline void Add_Edge(int x,int y,int w)
 23 {
 24     e[++tot].to=y;  e[tot].w=w;
 25     e[tot].next=fisrt[x];   fisrt[x]=tot;
 26 }
 27 
 28 inline int getn(int x,int y)
 29 {
 30     return x*(x-1)/2+y;
 31 }
 32 
 33 void init()
 34 {
 35     memset(fisrt,-1,sizeof(fisrt));
 36     scanf("%d",&l); n=getn(l,l);
 37     for(int i=1;i<=l;i++)
 38         for(int j=1;j<=i;j++)
 39             scanf("%d",&w[i][j]);
 40 }
 41 
 42 void getmap()//建圖從上向下建更方便
 43 {
 44     Add_Edge(2,1,w[2][1]);
 45     Add_Edge(3,1,w[2][2]);
 46     for(int i=2;i<=l;i++)
 47         for(int j=1;j<=i;j++)
 48         {
 49             int u=getn(i,j);
 50             if(j==1)
 51             {
 52                 Add_Edge(getn(i,i),u,w[i][i]);
 53                 Add_Edge(getn(i,j+1),u,w[i][j+1]);
 54                 if(i!=l)
 55                     Add_Edge(getn(i+1,i+1),u,w[i+1][i+1]),
 56                     Add_Edge(getn(i+1,j),u,w[i+1][j]),
 57                     Add_Edge(getn(i+1,j+1),u,w[i+1][j+1]);
 58             }
 59             else    if(j==i)
 60             {
 61                 Add_Edge(getn(i,j-1),u,w[i][j-1]);
 62                 Add_Edge(getn(i,1),u,w[i][1]);
 63                 if(i!=l)
 64                     Add_Edge(getn(i+1,j),u,w[i+1][j]),
 65                     Add_Edge(getn(i+1,1),u,w[i+1][1]),
 66                     Add_Edge(getn(i+1,j+1),u,w[i+1][j+1]);
 67             }
 68             else
 69             {
 70                 Add_Edge(getn(i,j-1),u,w[i][j-1]);
 71                 Add_Edge(getn(i,j+1),u,w[i][j+1]);
 72                 if(i!=l)
 73                     Add_Edge(getn(i+1,j),u,w[i+1][j]),
 74                     Add_Edge(getn(i+1,j+1),u,w[i+1][j+1]);
 75             }
 76         }
 77 }
 78 
 79 void SPFA(int s)
 80 {
 81     memset(d,0x37,sizeof(d));
 82     q.push(s);  d[s]=0;  in[s]=1;
 83     while(!q.empty())
 84     {
 85         int u=q.front();    q.pop();    in[u]=0;
 86         for(int i=fisrt[u];i!=-1;i=e[i].next)
 87         {
 88             int& v=e[i].to; int& w=e[i].w;
 89             if(d[v]>d[u]+w)
 90             {
 91                 d[v]=d[u]+w;
 92                 if(!in[v])
 93                 {
 94                     q.push(v);
 95                     in[v]=1;
 96                 }
 97             }
 98         }
 99     }
100     cout<<d[1]+w[1][1]<<endl;
101 }
102 
103 int main()
104 {
105     init();
106     getmap();
107     SPFA(getn(l,1));
108 }
View Code

?

?算法二:動態規劃

?說實話,上面那一長段的關于動規算法的描述,我是真沒看懂,直接看代碼還大概清楚一點。

下面代碼中,f[i][j]表示從(i,j)這個位置到達頂部(1,1)這個位置的最短距離。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <cstring>
 5 using namespace std;
 6 
 7 const int maxn=1005;
 8 int a[maxn][maxn];
 9 int f[maxn][maxn];
10 int n;
11 
12 int main()
13 {
14     cin>>n;
15     for(int i=1;i<=n;i++)
16         for(int j=1;j<=i;j++)
17         cin>>a[i][j];
18     f[1][1]=a[1][1];//終點處就直接是該點時間
19     for(int i=2;i<=n;i++)//一層一層往上推
20     {
21         for(int j=2;j<i;j++)//先求出從上一層推出來的最小值
22             f[i][j]=min(f[i-1][j],f[i-1][j-1])+a[i][j];
23         f[i][1]=min(f[i-1][1],f[i-1][i-1])+a[i][1];//特殊邊界點處理
24         f[i][i]=min(f[i-1][i-1],f[i-1][1])+a[i][i];//特殊邊界點處理
25         //同一層更新最優解
26         for(int k=i-1;k>0;k--)//從右往左推 從右往左走的情況更新
27             f[i][k]=min(f[i][k],f[i][k+1]+a[i][k]);
28         f[i][i]=min(f[i][i],f[i][1]+a[i][i]);
29 
30         for(int l=2;l<=i;l++)//從左往右推 從左往右走的情況更新
31             f[i][l]=min(f[i][l],f[i][l-1]+a[i][l]);
32             f[i][1]=min(f[i][1],f[i][i]+a[i][1]);
33         //我也沒太明白為何需要下面這兩個for,把上面的事情再做一遍。我把下面這兩個for屏蔽以后確實是可以AC的。假如真有原因,估計要讀上面那一長段文字了
34         for(int k=i-1;k>0;k--)//再推一遍從右往左推 從右往左走的情況更新
35             f[i][k]=min(f[i][k],f[i][k+1]+a[i][k]);
36             f[i][i]=min(f[i][i],f[i][1]+a[i][i]);
37 
38         for(int l=2;l<=i;l++)//再推一遍從左往右推 從左往右走的情況更新
39             f[i][l]=min(f[i][l],f[i][l-1]+a[i][l]);
40                 f[i][1]=min(f[i][1],f[i][i]+a[i][1]);
41     }
42     cout<<f[n][1]<<endl;
43 }

上面這一段代碼來自vijos討論版塊:https://vijos.org/p/1006/solution

下面是另一個動規代碼,可以與上面這一段互相對照理解。代碼來源:http://blog.csdn.net/Little_Flower_0/article/details/47945611

下面這段代碼中,d[i][j]表示從(i,j)這個位置到達底層的最短距離。

 1 #include<stdio.h>
 2 #define maxint 2000000000
 3 #define min(a,b) (a<b?a:b)
 4 long a[1000][1000]={0};
 5 long d[1000][1000]={0};
 6 int main()
 7 {
 8     long n,i,j;
 9     scanf("%ld",&n);
10     for(i=0;i<n;i++)
11       for(j=0;j<=i;j++)
12         scanf("%ld",&a[i][j]);
13 
14     for(i=0;i<n;i++)
15       for(j=0;j<=i;j++)
16         d[i][j]=maxint;
17 
18     for(i=0;i<n;i++)                                            //對最后一行的處理 
19       d[n-1][i]=a[n-1][i];
20     for(i=1;i<n;i++)
21       d[n-1][i]=d[n-1][i-1]+a[n-1][i];                          //因為最后一行右邊的點只能從左邊的推來,所以有了這個預處理 
22     for(i=n-1;i>=0;i--)                              
23       d[n-1][i]=min(d[n-1][i],d[n-1][(i+1)%n]+a[n-1][i]);       //往左走的話,肯定要先從左邊翻過去再向左走 
24 
25     for(i=n-2;i>=0;i--)
26     {
27        d[i][0]=min(d[i+1][0],d[i+1][1]);                        //對左邊界的處理 
28        d[i][0]=min(d[i][0],d[i+1][i+1]);
29        d[i][0]+=a[i][0];
30 
31        d[i][i]=min(d[i+1][0],d[i+1][i]);                        //對右邊界的處理 
32        d[i][i]=min(d[i][i],d[i+1][i+1]);
33        d[i][i]+=a[i][i];
34 
35        for(j=1;j<=i-1;j++)                                      //對中間位置的處理,這時候下面的一行已經處理完了 
36          d[i][j]=min(d[i+1][j],d[i+1][j+1])+a[i][j];
37 
38        d[i][0]=min(d[i][0],d[i][i]+a[i][0]);                    //左推與右推 
39        for(j=1;j<=i;j++)
40          d[i][j]=min(d[i][j],d[i][j-1]+a[i][j]);
41        for(j=i;j>=0;j--)
42          d[i][j]=min(d[i][j],d[i][(j+1)%(i+1)]+a[i][j]);
43 
44     }
45     printf("%ld\n",d[0][0]);
46     return 0;
47 }

?

轉載于:https://www.cnblogs.com/huashanqingzhu/p/7345648.html

總結

以上是生活随笔為你收集整理的vijos 1006 晴天小猪历险记之Hill——数字三角形的终极变化的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。